Skip to content

Common issues

The most common problems come from configuration that does not match what the composed code expects. notewright doctor catches most of them before deploy; this page covers the rest.

This is expected. The generated src/index.ts has non-compiling holes where you compose your providers. It will not compile until you install your provider packages and wire them into defineApp. See Quick start.

Extraction does nothing / AI Gateway errors

Section titled “Extraction does nothing / AI Gateway errors”

The follow-up pipeline reads AI_GATEWAY_ID, AI_GATEWAY_ACCOUNT_ID, and AI_GATEWAY_TOKEN and fails fast if any is missing or blank.

  • Confirm all three are set, and that AI_GATEWAY_TOKEN (a secret) was included in your --secrets-file at deploy.
  • Confirm the Anthropic key is stored in the gateway (BYOK) and the token has Run permission.
  • Run notewright doctor to confirm required vars declared in the fragment are present in wrangler.jsonc.

See AI Gateway setup.

Doctor requires Bun. The CLI imports your TypeScript entry directly, which pulls in agents and cloudflare: modules that plain Node cannot load. Install Bun 1.3.14+ and run under Bun. Node-only environments cannot run doctor.

A Durable Object only registers its cron on first start. After a fresh deploy, run notewright start (or call /health per agent) so each onStart() runs, then confirm with notewright schedules. See Syncing & backfill.

If doctor reports local migration files that are not applied, run the command it prints:

Terminal window
bunx wrangler d1 migrations apply <db> --remote

Use notewright doctor --check-remote to compare the remote d1_migrations table against your local files.

Durable Object binding or migration mismatch

Section titled “Durable Object binding or migration mismatch”

If doctor reports missing or extra DO bindings or migrations, your composed providers and wrangler.jsonc disagree. wrangler.jsonc is the canonical source; re-derive the build fragment from it rather than hand-editing the fragment. The core bindings (FOLLOW_UP_AGENT/v2, SPEAKER_CONTEXT_AGENT/v3) and the Granola provider’s GRANOLA_SYNC_AGENT/granola-v1 must all be present. See Durable Objects.

The connection resolver needs one of: --url + a secret, NOTEWRIGHT_URL + NOTEWRIGHT_SECRET, or a linked instance with a keychain secret. If you see “no instance to target”, run notewright login <url> or pass --url/--secret. See the CLI overview.

On platforms without a native keychain binding, the CLI falls back to a plain JSON file next to config.json. To force that fallback (for example in CI), set NOTEWRIGHT_DISABLE_KEYCHAIN=1.

Every HTTP route is guarded by SYNC_SHARED_SECRET. A 401 means the bearer token does not match the deployed secret; a 500 about an unconfigured secret means the instance has no SYNC_SHARED_SECRET set. Re-check the secret you linked with notewright login. See the HTTP API reference.