Troubleshooting
Trace symptoms to configuration, data, and execution stages to troubleshoot local development, authentication, payments, background jobs, and deployment.
When something goes wrong, identify which step did not complete before deciding what to change. This chapter contains six articles organized around the current default template's workflows. Problems in the same workflow are covered together, so you do not have to keep switching between authentication, email, and OAuth, or between payments and webhooks.
Find an article by symptom
| Symptom | Article | What to check |
|---|---|---|
| Installation, startup, or build failures, or content that does not update | Local development and builds | Node.js, initialization, configuration validation, content generation |
| Missing tables or data, migration failures, or constraint conflicts | Databases and migrations | Target database, existing schema, migration records |
| Sign-in redirects, verification code or email issues, or failed Google or GitHub sign-in | Sign-in, email, and OAuth | Cookies, verification status, email delivery mode, callback configuration |
| Checkout failures, access missing after payment, or webhook errors | Payments and webhooks | Stripe connections, event ledger, transactions, entitlement grants |
| Queue messages produce no results, recurring tasks do not run, or analytics has no data | Background jobs and analytics | Consumer dispatch, Events, Commands, Cron |
| Interrupted first deployment, missing resources, domain issues, or stale production content | Deployment, resources, and domains | Release stage, resource ownership, runtime configuration, content synchronization |
1. Establish reproducible conditions
Record the environment, code version, URL, time of the operation, and shortest steps to reproduce the issue. For example, “In production, a regular account purchased the yearly plan. Stripe shows the payment as complete, but the product is still unavailable after refreshing the product page” is easier to investigate than “Payments are broken.”
Inspect local and production environments separately. Missing records in local D1 do not show whether a production payment was saved. Likewise, changing local .env does not let you test that change in production.
| Evidence | Where to find it | Purpose |
|---|---|---|
| Request method, path, HTTP status, and response body | Browser Network panel | Distinguish a request that was never sent from an endpoint rejection or server exception |
| First exception, request time, and correlation ID | Local terminal, Worker logs | Identify the failed step and correlate subsequent processing |
| Event ID, Checkout ID, and internal execution ID | Payment platform and application logs | Trace the same business operation without guessing based on similar timestamps |
| Configuration keys, resource names, and IDs | config/, wrangler.jsonc | Confirm which targets the application is using |
| Table schemas, statuses, and record timestamps | Read-only queries against the relevant D1 database | Determine which steps have been persisted |
An API's code may be a numeric result code, part of a third-party protocol, or absent altogether. Look up numeric codes in src/errors.ts. Do not assume every response is a complete APIResponse<T>.
Redact cookies, tokens, secrets, verification codes, and recipient information before sharing troubleshooting details. Local email previews include message bodies, so check terminal output before copying it as well.
2. Check diagnostics, then verify the workflow
From the root of the initialized project, choose the check for your environment:
# Local configuration
npm run doctor# Production configuration and Cloudflare account access
npm run doctor:remotedoctor checks configuration, variables, binding names, database directories, and related settings. doctor:remote reads .env.production and also checks that remote resource IDs are filled in and that the current identity can access the configured account.
These commands do not fully test your production services. Passing the checks does not prove that every resource exists, that Resend delivered an email, that Stripe completed a callback, or that a Queue task ran. Disabled optional services may produce notices or warnings. Evaluate them in the context of the feature you are testing.
3. Continue from the last successful step
A typical payment flow is:
Create Checkout → The user pays → Verify the webhook signature
→ Update payment records → Create a business Event → Execute Commands → Grant user accessIf the correct payment event has arrived, inspect payment records and access processing next. There is no need to keep changing the Checkout page. If no callback has arrived, address the callback URL, secret, and delivery issues first.
The same applies to background jobs. Completion of queue.send(), message acknowledgment, Command success, and completion by an external service are separate stages. Verify each one separately.
4. Verify the fix
Repeat the same reproduction case and check related failure scenarios. For example, after correcting a plan mapping, check both that a new payment grants access and that duplicate callbacks do not create duplicate grants.
After code changes, run the project's npm run verify. After changing configuration or provider settings, also test the relevant workflow. Successful compilation does not prove that an external service is available.
Preserve evidence of the failure
Do not reset the production database, delete payment event records, or change SAAS_SECRET just to make an error disappear. Locate the failure before choosing a recovery method. Resetting a database deletes its data, and changing the master secret may make existing encrypted data unreadable.
Common errors
| Error or message | Next step |
|---|---|
Configuration validation failed at startup | Inspect the reported field path and check configuration values and references |
no such table | Check the D1 binding, environment, and migration status |
Binding ... not found | Check the actual bindings. Generating types does not create resources |
redirect_uri_mismatch | Compare the full callback URLs configured on the third-party platform and used by the application |
emailSendTooOften | Check email sending quotas and duplicate submissions. Do not keep retrying |
PAYMENT_NOT_CONFIGURED | Check the current Worker's Stripe connection and keys |
WEBHOOK_BUSY | Inspect the event's processing lease and logs. Do not delete the ledger |
paymentsProductAlreadyPurchased | Check the plan's repeat-purchase rules and existing purchase records |
Command outcome needs manual review | Check external effects first to avoid duplicate sends or grants |
| 401, 403, 429 | Use the response body to distinguish session, permission, origin validation, and rate limiting issues |
For exact field definitions, see the reference. To complete a release from the beginning, see deployment.