Skip to content

Troubleshooting deployments

Failure modes for scripts/install.sh and manual pulumi / wrangler runs, grounded in the current Cloudflare pipeline (provision → deploy → seed → verify). Each entry gives the symptom, the cause, and the exact recovery command. Deployment-specific Cloudflare failure modes surface in the install report (install-report.json).


Preflight failures

missing required command: pulumi / wrangler

Cause — the installer’s preflight requires Node 22+, pnpm, python3, Pulumi, and Wrangler on PATH.

Fix

Terminal window
npm i -g pnpm && corepack enable
curl -fsSL https://get.pulumi.com | sh # Pulumi CLI
npm i -g wrangler # or: npx wrangler <cmd>

required env var CLOUDFLARE_API_TOKEN is not set

Cause — live runs (not --dry-run) require the Cloudflare credentials.

Fix

Terminal window
export CLOUDFLARE_API_TOKEN=<token>
export CLOUDFLARE_ACCOUNT_ID=<account-id>
export PULUMI_CONFIG_PASSPHRASE=<passphrase> # may be empty, must be defined

Use the --dry-run flag to print every action without touching a live account.


Provision stage (Pulumi)

incorrect passphrase

Cause — PULUMI_CONFIG_PASSPHRASE differs from the passphrase that encrypted the stack’s secrets.

Fix — restore the original passphrase. It cannot be recovered; a wrong value means the stack secrets are unreadable and must be re-set deliberately:

Terminal window
cd infra
PULUMI_CONFIG_PASSPHRASE=<passphrase> pulumi stack select mnemose-<env>
PULUMI_CONFIG_PASSPHRASE=<passphrase> pulumi refresh --yes

Missing required config variable: mnemose:env / mnemose:accountId

Cause — infra/index.ts requires both.

Fix

Terminal window
cd infra
pulumi config set mnemose:env <dev|staging|production>
pulumi config set mnemose:accountId <cloudflare-account-id>

invalid environment name: <env>

Cause — cloudflareResourceNames() only accepts lowercase alphanumeric names with hyphens (/^[a-z0-9][a-z0-9-]*$/). Every resource name is derived from it.

Fix — rename the environment to a conforming value (e.g. dev, not Dev or dev_1) and re-run the provision stage.

Pulumi backend unreachable

Cause — PULUMI_BACKEND_URL points at a state backend the token cannot reach.

Fix

Terminal window
cd infra && pulumi login <backend-url>
cd infra && pulumi stack select mnemose-<env>
cd infra && pulumi refresh --yes

Deploy stage (Wrangler)

A request to the Cloudflare API failed / 403

Cause — the API token lacks the permission for the resource being deployed (Workers Scripts, D1, R2, KV, Queues, Pages, or DNS Zone edit).

Fix — widen the token’s permissions, then re-run:

Terminal window
./scripts/install.sh --env <env> --stage deploy

Queue consumers are missing after a deploy

Cause — consumers are bound in a second Pulumi pass, which only runs when deployConsumers is set. A deploy that skipped it leaves Queues with no consumer.

Fix

Terminal window
cd infra
pulumi config set mnemose:deployConsumers true
PULUMI_CONFIG_PASSPHRASE=*** pulumi up --yes

No queue named mnemose-commands-<env> in a Worker deploy

Cause — Wrangler deploys bindings declared in wrangler.toml; the queues must already exist (created by the provision stage).

Fix — run the provision stage first, then re-run deploy:

Terminal window
./scripts/install.sh --env <env> --stage provision
./scripts/install.sh --env <env> --stage deploy

Seed stage (D1 + KV)

wrangler d1 migrations apply reports already-applied migrations

Cause — migrations are tracked; re-applying is a no-op, not a failure.

Fix — none needed. Confirm the schema landed:

Terminal window
npx wrangler d1 execute mnemose-<env> --remote \
--command "SELECT name FROM sqlite_master WHERE type='table' AND name='domain_events';"

config KV id not resolved; skip KV hydration

Cause — the seed stage could not map the namespace title (mnemose-config-<env>) to an id.

Fix — set it explicitly and re-run the stage:

Terminal window
export MNEMOSE_CONFIG_KV_ID=<namespace-id>
./scripts/install.sh --env <env> --stage seed

Verify stage

GET <origin>/health returns non-200

Cause — usually a route/DNS gap: the custom domain does not yet point at the Worker route, or the route was never created because mnemose:zoneId was unset.

Fix

Terminal window
curl -sS https://<origin>/health | head
npx wrangler deployments list --name mnemose-gateway-<env>

If the route is missing, set the zone and re-run the provision stage:

Terminal window
cd infra && pulumi config set mnemose:zoneId <zone-id> && pulumi up --yes

GraphQL probe returns UNAUTHENTICATED

Cause — expected when the verify probe sends no credentials: the gateway enforces Cloudflare Access outside development.

Fix — run the probe with the Access token, or against a dev deployment with DEV_AUTH_TOKEN set. The gateway returns {"errors":[{"message":"Missing Authorization header", ...}]} for unauthenticated requests by design.

D1 system tenant check fails

Cause — the seed stage did not run, or the tenant id differs from the one the verify script expects.

Fix

Terminal window
npx wrangler d1 execute mnemose-<env> --remote \
--command "SELECT id, name FROM tenants;"
export SYSTEM_TENANT_ID=<id>
./scripts/install.sh --env <env> --stage verify

General recovery

Resume a single phase without re-running the whole pipeline:

Terminal window
./scripts/install.sh --env <env> --stage provision|deploy|seed|verify

Every phase is idempotent. Pulumi converges to the declared state, Wrangler overwrites the deployed Worker, D1 migrations are tracked, and the tenant/queue upserts use conflict-ignore semantics.

Inspect the machine-readable result of the last run:

Terminal window
cat install-report.json