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
npm i -g pnpm && corepack enablecurl -fsSL https://get.pulumi.com | sh # Pulumi CLInpm 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
export CLOUDFLARE_API_TOKEN=<token>export CLOUDFLARE_ACCOUNT_ID=<account-id>export PULUMI_CONFIG_PASSPHRASE=<passphrase> # may be empty, must be definedUse 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:
cd infraPULUMI_CONFIG_PASSPHRASE=<passphrase> pulumi stack select mnemose-<env>PULUMI_CONFIG_PASSPHRASE=<passphrase> pulumi refresh --yesMissing required config variable: mnemose:env / mnemose:accountId
Cause — infra/index.ts requires both.
Fix
cd infrapulumi 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
cd infra && pulumi login <backend-url>cd infra && pulumi stack select mnemose-<env>cd infra && pulumi refresh --yesDeploy 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:
./scripts/install.sh --env <env> --stage deployQueue 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
cd infrapulumi config set mnemose:deployConsumers truePULUMI_CONFIG_PASSPHRASE=*** pulumi up --yesNo 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:
./scripts/install.sh --env <env> --stage provision./scripts/install.sh --env <env> --stage deploySeed 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:
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:
export MNEMOSE_CONFIG_KV_ID=<namespace-id>./scripts/install.sh --env <env> --stage seedVerify 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
curl -sS https://<origin>/health | headnpx wrangler deployments list --name mnemose-gateway-<env>If the route is missing, set the zone and re-run the provision stage:
cd infra && pulumi config set mnemose:zoneId <zone-id> && pulumi up --yesGraphQL 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
npx wrangler d1 execute mnemose-<env> --remote \ --command "SELECT id, name FROM tenants;"export SYSTEM_TENANT_ID=<id>./scripts/install.sh --env <env> --stage verifyGeneral recovery
Resume a single phase without re-running the whole pipeline:
./scripts/install.sh --env <env> --stage provision|deploy|seed|verifyEvery 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:
cat install-report.json