# Common Issues and Troubleshooting

> This document details all 6 documented issues that commonly affect Cloudflare Workers projects, with detailed explanations and fixes.

- Skill: `tools-only/common-issues-and-troubleshooting-2` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add tools-only/common-issues-and-troubleshooting-2`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/common-issues-and-troubleshooting-2/raw
- Safety review: pending (external: skill-scanner PASS, skillspector CAUTION)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-29
- Page: https://skillmd.com/skills/tools-only/common-issues-and-troubleshooting-2

---

# Common Issues and Troubleshooting

**Last Updated**: 2025-10-20

This document details all 6 documented issues that commonly affect Cloudflare Workers projects, with detailed explanations and fixes.

---

## Table of Contents

1. [Issue #1: Export Syntax Error](#issue-1-export-syntax-error)
2. [Issue #2: Static Assets Routing Conflicts](#issue-2-static-assets-routing-conflicts)
3. [Issue #3: Scheduled/Cron Not Exported](#issue-3-scheduledcron-not-exported)
4. [Issue #4: HMR Race Condition](#issue-4-hmr-race-condition)
5. [Issue #5: Static Assets Upload Race](#issue-5-static-assets-upload-race)
6. [Issue #6: Service Worker Format Confusion](#issue-6-service-worker-format-confusion)

---

## Issue #1: Export Syntax Error

### Symptoms

```
Error: Cannot read properties of undefined (reading 'map')
```

Deployment fails with TypeError during build or runtime.

### Source

- **GitHub Issue**: [honojs/hono #3955](https://github.com/honojs/hono/issues/3955)
- **Related**: [honojs/vite-plugins #237](https://github.com/honojs/vite-plugins/issues/237)
- **Reported**: February 2025

### Root Cause

When using Hono with Vite's build tools, the incorrect export pattern breaks the `this` context:

```typescript
// ❌ WRONG: This causes the error
export default {
  fetch: app.fetch
}
```

**Why it breaks:**
- Vite's bundler transforms the code
- The `app.fetch` binding loses its `this` context
- When Cloudflare calls `fetch()`, `this` is `undefined`
- Hono tries to access `this.routes.map(...)` → Error

### Fix

Use the direct export pattern:

```typescript
import { Hono } from 'hono'

const app = new Hono()

// Define routes...

// ✅ CORRECT
export default app
```

**Why this works:**
- Hono's app object already implements the fetch handler
- No context binding is lost
- Vite can properly bundle the code

### Exception: When You Need Multiple Handlers

If you need scheduled/tail handlers, use Module Worker format:

```typescript
export default {
  fetch: app.fetch,
  scheduled: async (event, env, ctx) => {
    console.log('Cron triggered:', event.cron)
  }
}
```

This works because Cloudflare's runtime handles the binding correctly for Module Workers.

### How to Verify Fix

1. Check your `src/index.ts` export
2. Ensure it's `export default app`
3. Run `npm run dev` → Should start without errors
4. Run `npm run deploy` → Should deploy successfully
5. Test API endpoints → Should return JSON (not errors)

---

## Issue #2: Static Assets Routing Conflicts

### Symptoms

- API routes return `index.html` instead of JSON
- API endpoints return status 200 but wrong content-type (text/html instead of application/json)
- Browser console shows HTML when expecting JSON

### Example

```bash
curl http://localhost:8787/api/hello
# Expected: {"message":"Hello"}
# Actual: <!DOCTYPE html><html>...
```

### Source

- **GitHub Issue**: [workers-sdk #8879](https://github.com/cloudflare/workers-sdk/issues/8879)
- **Reported**: April 2025

### Root Cause

The `not_found_handling: "single-page-application"` configuration creates a fallback:

```
Request → File not found → Return index.html
```

**Without `run_worker_first`:**
1. Request to `/api/hello`
2. Static Assets handler checks: "Does `/api/hello` file exist?"
3. No → SPA fallback → Returns `public/index.html`
4. Your Worker never runs!

### Fix

Add `run_worker_first` to `wrangler.jsonc`:

```jsonc
{
  "assets": {
    "directory": "./public/",
    "binding": "ASSETS",
    "not_found_handling": "single-page-application",
    "run_worker_first": ["/api/*"]  // ← CRITICAL
  }
}
```

**What this does:**
- Requests matching `/api/*` go to your Worker FIRST
- If Worker doesn't handle it, then try Static Assets
- Ensures API routes are never intercepted by SPA fallback

### Advanced Configuration

```jsonc
{
  "assets": {
    "run_worker_first": [
      "/api/*",
      "/auth/*",
      "/webhooks/*",
      "/_app/*"
    ]
  }
}
```

### How to Verify Fix

1. Start dev server: `npm run dev`
2. Test API endpoint:
   ```bash
   curl -i http://localhost:8787/api/hello
   ```
3. Check response:
   - ✅ `Content-Type: application/json`
   - ✅ JSON body
4. Test static file:
   ```bash
   curl -i http://localhost:8787/
   ```
5. Check response:
   - ✅ `Content-Type: text/html`
   - ✅ HTML body

---

## Issue #3: Scheduled/Cron Not Exported

### Symptoms

```
Error: Handler does not export a scheduled() function
```

Deployment succeeds, but cron triggers fail.

### Source

- **GitHub Issue**: [honojs/vite-plugins #275](https://github.com/honojs/vite-plugins/issues/275)
- **Reported**: July 2025

### Root Cause

The `@hono/vite-build/cloudflare-workers` plugin **only supports the `fetch` handler**.

If you use:
```typescript
export default app  // Only exports fetch handler
```

...then scheduled/tail handlers are not exported.

### Fix Option 1: Use Module Worker Format

```typescript
import { Hono } from 'hono'

const app = new Hono()

// Define routes...

// ✅ Export multiple handlers
export default {
  fetch: app.fetch,

  scheduled: async (event, env, ctx) => {
    console.log('Cron triggered:', event.cron)
    // Your scheduled logic here
  },

  tail: async (events, env, ctx) => {
    // Tail handler logic
    console.log('Tail events:', events)
  }
}
```

### Fix Option 2: Use @cloudflare/vite-plugin

Instead of `@hono/vite-build/cloudflare-workers`, use the official Cloudflare plugin:

```bash
npm uninstall @hono/vite-build
npm install -D @cloudflare/vite-plugin
```

Update `vite.config.ts`:
```typescript
import { defineConfig } from 'vite'
import { cloudflare } from '@cloudflare/vite-plugin'

export default defineConfig({
  plugins: [cloudflare()],
})
```

This plugin supports all handler types.

### Configure Cron in wrangler.jsonc

```jsonc
{
  "triggers": {
    "crons": ["0 0 * * *"]  // Daily at midnight UTC
  }
}
```

### How to Verify Fix

1. Deploy: `npm run deploy`
2. Trigger manually:
   ```bash
   wrangler deploy && wrangler tail
   ```
3. Wait for cron or trigger via dashboard
4. Check logs for scheduled handler output

---

## Issue #4: HMR Race Condition

### Symptoms

```
Error: A hanging Promise was canceled
```

- Development server crashes during file changes
- Happens with rapid HMR updates
- Requires manual restart

### Source

- **GitHub Issue**: [workers-sdk #9518](https://github.com/cloudflare/workers-sdk/issues/9518)
- **Related**: [workers-sdk #9249](https://github.com/cloudflare/workers-sdk/issues/9249)
- **Reported**: June 2025

### Root Cause

**Race condition in `@cloudflare/vite-plugin` versions 1.1.1 through 1.11.x:**

1. File change detected
2. Vite triggers HMR
3. Plugin cancels old Worker instance
4. New instance starts before old one fully terminates
5. Promise cancellation error thrown

### Fix

Update to latest `@cloudflare/vite-plugin`:

```bash
npm install -D @cloudflare/vite-plugin@1.17.1
```

**Fixed in version 1.13.13** (October 2025)

### Alternative: Configure Vite with Persistence

If updating doesn't fix it, try:

```typescript
// vite.config.ts
import { defineConfig } from 'vite'
import { cloudflare } from '@cloudflare/vite-plugin'

export default defineConfig({
  plugins: [
    cloudflare({
      persist: true,  // Persist state between HMR updates
    }),
  ],
})
```

### How to Verify Fix

1. Start dev server: `npm run dev`
2. Make rapid file changes (edit `src/index.ts` 5 times quickly)
3. Check terminal:
   - ✅ No "hanging Promise" errors
   - ✅ HMR updates smoothly
4. Test API endpoint after each change:
   ```bash
   curl http://localhost:8787/api/hello
   ```

---

## Issue #5: Static Assets Upload Race

### Symptoms

- Deployment fails **non-deterministically** in CI/CD
- Works locally, fails in CI randomly
- Error messages vary:
  - "Failed to upload assets"
  - "Timeout during asset upload"
  - "Asset manifest mismatch"

### Source

- **GitHub Issue**: [workers-sdk #7555](https://github.com/cloudflare/workers-sdk/issues/7555)
- **Reported**: March 2025

### Root Cause

**Race condition during parallel asset uploads:**

1. Wrangler uploads multiple assets simultaneously
2. Cloudflare's asset store processes uploads
3. Manifest is generated before all uploads complete
4. Deployment validation fails

**Most common in CI/CD** because:
- Network latency varies
- Parallel execution timing is different
- No user interaction to retry

### Fix Option 1: Use Wrangler 4.x+ (Recommended)

Wrangler 4.x includes improved upload logic:

```bash
npm install -D wrangler@latest
```

**Improvements in 4.x:**
- Sequential upload of critical assets
- Better retry logic
- Manifest generation after all uploads complete

### Fix Option 2: Add Retry Logic to CI/CD

```yaml
# GitHub Actions example
- name: Deploy to Cloudflare
  run: |
    for i in {1..3}; do
      npm run deploy && break || sleep 10
    done
```

```bash
# Shell script
#!/bin/bash
for i in {1..3}; do
  npm run deploy && break || sleep 10
done
```

### Fix Option 3: Reduce Asset Count

If you have many small files, bundle them:

```typescript
// vite.config.ts
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
        },
      },
    },
  },
})
```

### How to Verify Fix

1. Deploy locally 5 times:
   ```bash
   for i in {1..5}; do npm run deploy; done
   ```
2. All deployments should succeed
3. Run in CI/CD pipeline
4. Check logs for upload errors

---

## Issue #6: Service Worker Format Confusion

### Symptoms

- Using deprecated `addEventListener('fetch', ...)` pattern
- TypeScript errors about missing types
- Bindings don't work (KV, D1, R2)
- Modern Cloudflare features unavailable

### Source

- **Cloudflare Migration Guide**: https://developers.cloudflare.com/workers/configuration/compatibility-dates/
- **Multiple Stack Overflow questions** (2024-2025)

### Root Cause

**Old tutorials and templates** still use the deprecated Service Worker format:

```typescript
// ❌ DEPRECATED: Service Worker format
addEventListener('fetch', (event) => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  return new Response('Hello World')
}
```

**Problems with this format:**
- Doesn't support bindings (KV, D1, R2, etc.)
- No TypeScript types
- No environment variable access
- Deprecated since Workers v2 (2021)

### Fix: Use ES Module Format

```typescript
// ✅ CORRECT: ES Module format
export default {
  fetch(request, env, ctx) {
    return new Response('Hello World')
  }
}
```

**With Hono:**
```typescript
import { Hono } from 'hono'

const app = new Hono()

app.get('/', (c) => c.text('Hello World'))

export default app
```

### Migration Steps

1. **Remove `addEventListener`**:
   ```diff
   - addEventListener('fetch', (event) => {
   -   event.respondWith(handleRequest(event.request))
   - })
   ```

2. **Change to ES Module export**:
   ```diff
   + export default {
   +   fetch(request, env, ctx) {
   +     return handleRequest(request, env)
   +   }
   + }
   ```

3. **Update function signatures** to accept `env`:
   ```diff
   - async function handleRequest(request) {
   + async function handleRequest(request, env) {
       // Now you can access env.MY_KV, env.DB, etc.
   ```

4. **Update `wrangler.toml` → `wrangler.jsonc`**:
   ```bash
   # Convert TOML to JSONC (preferred since Wrangler v3.91.0)
   ```

### How to Verify Fix

1. Check `src/index.ts`:
   - ✅ No `addEventListener`
   - ✅ Has `export default`
2. Check you can access bindings:
   ```typescript
   const value = await env.MY_KV.get('key')
   ```
3. TypeScript types work:
   ```typescript
   type Bindings = {
     MY_KV: KVNamespace
   }
   ```

---

## General Troubleshooting Tips

### Check Package Versions

```bash
npm list hono @cloudflare/vite-plugin wrangler
```

**Expected (as of 2026-01-06):**
- `hono@4.11.3`
- `@cloudflare/vite-plugin@1.17.1`
- `wrangler@4.54.0`

### Clear Wrangler Cache

```bash
rm -rf node_modules/.wrangler
rm -rf .wrangler
npm run dev
```

### Check Wrangler Config

```bash
wrangler whoami  # Verify authentication
wrangler dev --local  # Test without deploying
```

### Enable Verbose Logging

```bash
WRANGLER_LOG=debug npm run dev
WRANGLER_LOG=debug npm run deploy
```

### Check Browser Console

Many issues are visible in the browser:
- Open DevTools → Network tab
- Check response Content-Type
- Check response body
- Look for CORS errors

### Test with curl

```bash
# Test API endpoint
curl -i http://localhost:8787/api/hello

# Test POST
curl -X POST http://localhost:8787/api/echo \
  -H "Content-Type: application/json" \
  -d '{"test":"data"}'

# Test static file
curl -i http://localhost:8787/styles.css
```

---

## Issue Summary Table

| Issue | Error Message | Source | Fix |
|-------|---------------|--------|-----|
| **#1** | "Cannot read properties of undefined" | hono #3955 | `export default app` |
| **#2** | API routes return HTML | workers-sdk #8879 | `run_worker_first: ["/api/*"]` |
| **#3** | "Handler does not export scheduled()" | vite-plugins #275 | Module Worker format or @cloudflare/vite-plugin |
| **#4** | "A hanging Promise was canceled" | workers-sdk #9518 | Update to vite-plugin@1.17.1+ |
| **#5** | Non-deterministic deployment failures | workers-sdk #7555 | Use Wrangler 4.x+ with retry |
| **#6** | Service Worker format issues | Cloudflare migration | Use ES Module format |

---

## Getting Help

If you encounter issues not covered here:

1. **Check official docs**:
   - Cloudflare Workers: https://developers.cloudflare.com/workers/
   - Hono: https://hono.dev/

2. **Search GitHub issues**:
   - workers-sdk: https://github.com/cloudflare/workers-sdk/issues
   - hono: https://github.com/honojs/hono/issues

3. **Ask in Discord**:
   - Cloudflare Developers: https://discord.gg/cloudflaredev
   - Hono: https://discord.gg/hono

4. **Check Stack Overflow**:
   - Tag: `cloudflare-workers`

---

**All issues documented with GitHub sources** ✅
**All fixes production-tested** ✅

