Skip to content

fix(core): don't treat transient setup-probe DB errors as a fresh install#1345

Merged
ascorbic merged 1 commit into
mainfrom
fix/setup-probe-transient-error
Jun 5, 2026
Merged

fix(core): don't treat transient setup-probe DB errors as a fresh install#1345
ascorbic merged 1 commit into
mainfrom
fix/setup-probe-transient-error

Conversation

@scottbuscemi
Copy link
Copy Markdown
Collaborator

What does this PR do?

Fixes logged-in and anonymous visitors being redirected to /_emdash/admin/setup when viewing ordinary frontend pages (e.g. a category page) on a fully set-up site.

The anonymous fast-path "setup probe" in packages/core/src/astro/middleware.ts queries _emdash_migrations to detect a fresh, un-migrated database. Its catch block treated every error as "fresh install":

} catch {
    // Table doesn't exist -> fresh database, redirect to setup
    return context.redirect("/_emdash/admin/setup");
}

On a deployed site the migrations table exists, but that probe query can still fail transiently — D1 "Network connection lost"/D1_ERROR, a read replica being briefly unavailable, a query timeout, a cold-start race before the binding is ready, or a locked SQLite DB. Any of those was misread as "no database yet" and bounced a real visitor to the setup wizard.

This is the only place in the codebase that redirected on any DB error. Everywhere else (middleware/setup.ts, typegen.ts, query.ts, loader.ts, handlers, taxonomies, bylines) uses the dialect-aware isMissingTableError() helper to distinguish a genuinely-missing table from other failures.

Changes:

  • The probe now redirects only when isMissingTableError(error) is true. Other errors are logged (non-fatal) and the page renders normally.
  • The setupVerified flag is moved from a module-scoped let onto a globalThis Symbol.for("emdash:setup-verified") singleton, matching the pattern in request-cache.ts. Per AGENTS.md, a plain module-scoped let gets duplicated across SSR chunks, which made the probe re-run far more often than intended — and each re-run was another chance to hit the bug.

(Logged-in users normally skip this path, but fall into it when the network-backed session lookup transiently returns null, which is why the report noted logged-in users specifically.)

Closes #

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes (core typechecks clean after building registry-client; the pre-existing @emdash-cms/registry-client/env resolution failures on main are unrelated to this change)
  • pnpm lint passes (pnpm lint:json reports 0 diagnostics)
  • pnpm test passes (or targeted tests for my change) — ran tests/unit/astro/ + tests/unit/middleware/, 96 passed
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation (if applicable) — n/a, no admin UI strings; the redirect target is a fixed route path
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion — n/a, bug fix

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Claude Opus 4.8 (opencode)

Screenshots / test output

Regression test added to tests/unit/astro/middleware-prerender.test.ts:

  • "redirects to setup when the migrations table is genuinely missing" — passes
  • "does NOT redirect to setup on a transient DB error (regression)" — fails against the old bare-catch, passes with the fix

Verified the transient-error test fails on the pre-fix code (bare catch redirects) and passes after the fix, while the missing-table test passes in both — confirming the test is specific to the bug.

 Test Files  12 passed (12)
      Tests  96 passed (96)

The anonymous fast-path setup probe in the Astro middleware queries
`_emdash_migrations` to detect a fresh, un-migrated database. Its catch
block treated every error as "fresh install" and redirected to
`/_emdash/admin/setup`, so a transient DB failure (D1 connection loss,
replica unavailable, query timeout, cold-start race, locked SQLite)
wrongly bounced real visitors on a set-up site to the setup wizard.

Only redirect when the error is a genuinely-missing table (via the
shared `isMissingTableError` helper); otherwise log and render the page.

Also move the `setupVerified` flag onto a globalThis Symbol.for
singleton so it isn't duplicated across SSR chunks — a plain module-scoped
`let` became multiple variables, making the probe re-run far more often
than intended (and each re-run was another chance to hit the bug).

Adds regression tests: a missing migrations table still redirects to
setup; a transient probe error renders the page and does not redirect.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 4, 2026

🦋 Changeset detected

Latest commit: 4ae2f2d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 14 packages
Name Type
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/admin Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
create-emdash Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added review/needs-review No maintainer or bot review yet area/core size/M labels Jun 4, 2026
@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
docs 4ae2f2d Jun 04 2026, 08:02 PM

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Jun 4, 2026

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@1345

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@1345

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@1345

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@1345

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@1345

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@1345

emdash

npm i https://pkg.pr.new/emdash@1345

create-emdash

npm i https://pkg.pr.new/create-emdash@1345

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@1345

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@1345

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@1345

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@1345

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@1345

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@1345

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@1345

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@1345

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@1345

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@1345

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@1345

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@1345

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@1345

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@1345

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@1345

commit: 4ae2f2d

@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-demo-cache 4ae2f2d Jun 04 2026, 08:05 PM

@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
emdash-playground 4ae2f2d Jun 04 2026, 08:05 PM

Copy link
Copy Markdown
Contributor

@emdashbot emdashbot Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR correctly fixes a real bug where transient database errors in the anonymous setup probe were being misread as "fresh install," causing visitors on fully-set-up sites to be redirected to /_emdash/admin/setup.

Approach: Sound. The author correctly identified that the bare catch block was the only place in the codebase not using the dialect-aware isMissingTableError() helper to distinguish a missing table from other failures. Limiting the redirect to genuinely-missing-table errors, and logging everything else as non-fatal, is the right behavior for a production site.

Global singleton: Moving setupVerified from a module-scoped let onto a globalThis Symbol.for singleton matches the established pattern in request-cache.ts, settings/index.ts, and other core modules. This avoids Vite SSR chunk duplication that was making the probe re-run more often than intended. The implementation (setupFlagStore[SETUP_VERIFIED_KEY] === true) is safe and consistent with siblings.

Tests: The regression test in middleware-prerender.test.ts is focused — it confirms that a missing table still redirects and that a D1 connection-lost error no longer does. The resetSetupVerified() helper in beforeEach correctly resets the global singleton between test runs.

Conventions: I checked for AGENTS.md violations — no new SQL queries (no injection risk), no content-table queries (no locale-filter concern), no admin UI strings (no Lingui or RTL issue). A changeset is present.

Code quality: The diff is focused and minimal. I found nothing worth flagging. LGTM.

@github-actions github-actions Bot added review/approved Approved; no new commits since and removed review/needs-review No maintainer or bot review yet labels Jun 4, 2026
@ascorbic ascorbic merged commit 80f2925 into main Jun 5, 2026
48 of 49 checks passed
@ascorbic ascorbic deleted the fix/setup-probe-transient-error branch June 5, 2026 10:22
@emdashbot emdashbot Bot mentioned this pull request Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core review/approved Approved; no new commits since size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants