Skip to content

Inherit the index entry's error status on card responses instead of hardcoding 500#5026

Merged
habdelra merged 9 commits into
mainfrom
cs-11293-card-response-inherit-error-status
May 30, 2026
Merged

Inherit the index entry's error status on card responses instead of hardcoding 500#5026
habdelra merged 9 commits into
mainfrom
cs-11293-card-response-inherit-error-status

Conversation

@habdelra
Copy link
Copy Markdown
Contributor

Background and Goal

When the realm-server serves a card whose index entry is in an error state, the HTTP response status was always 500, even though the index entry already records the real cause (e.g. an auth 403 or a validation 422). Cold-load consumers — browsers, AI tools, link checkers, HTTP caches — branch on status, so every errored card looked like a realm outage.

This makes the card response inherit the index entry's status instead of hardcoding 500, while keeping 404 reserved for a genuinely missing card.

Where to start

  • packages/runtime-common/realm.ts — the error-row branch of the card GET handler now derives the response status from errorDetail.status.
  • packages/runtime-common/error.tssystemError grows an optional status (defaults to 500).
  • packages/realm-server/tests/card-endpoints-test.ts — parametrized coverage over the status-selection rule.

Key decisions

  • A card that exists but is in an error state is never 404. 404 stays reserved for a missing index row (notFound), so a 404 on a card GET is an unambiguous "this card no longer exists" signal — which the host store's reload-on-invalidation path relies on to detect deletions. A recorded 404 (e.g. an error whose underlying cause was a missing linked instance) therefore falls back to 500. Because the realm upholds that invariant, the store needs no change.
  • Only real HTTP error statuses in 4xx/5xx (other than 404) are mirrored; non-HTTP failures (a fetch failure recorded as status 0) and out-of-range values fall back to 500.
  • The JSON:API body is unchanged — it still carries the real underlying status so consumers can see the precise cause regardless of the HTTP status.

Stacked on #5022.

…ys 500

A GET on a card whose index entry is in an error state now returns the
underlying error's HTTP status (auth 401/403, validation 422, upstream
5xx) rather than flattening everything to 500. `systemError` grows an
optional `status` that defaults to 500.

404 is never mirrored: an existing-but-errored card is not "not found".
404 remains reserved for a missing index row (`notFound`) so a 404 on a
card GET stays an unambiguous "this card no longer exists" signal — which
is what the host store's reload path relies on to detect deletions. A
recorded 404, a non-HTTP failure (status 0), or any out-of-range value
falls back to 500. The JSON:API body still carries the real underlying
status so consumers can see the precise cause.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aa77d53418

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/runtime-common/realm.ts
…es can't blow up the response

CardError's constructor derives its title from `getReasonPhrase`, which
throws for unregistered HTTP codes. Now that the error-row response
mirrors the underlying status, a proxied upstream code (e.g. 520/499)
could reach that fallback and turn the error response itself into an
unhandled failure. Supply the title explicitly from the non-throwing
`statuses` lookup, backstopped with a generic phrase.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates card GET error responses so existing index error rows return the underlying HTTP error status when safe, while preserving 404 exclusively for truly missing cards.

Changes:

  • Derives card error-row HTTP status from the persisted index error status, with fallbacks to 500 for 404, non-error, and out-of-range statuses.
  • Extends systemError to accept an optional response status and safely title unknown in-range status codes.
  • Adds coverage for mirrored statuses and fallback behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
packages/runtime-common/realm.ts Selects the HTTP status for card GET index-error responses from the stored error detail.
packages/runtime-common/error.ts Adds optional status support to systemError and avoids throwing on unregistered status titles.
packages/realm-server/tests/card-endpoints-test.ts Adds matrix-style assertions for HTTP status mirroring and JSON:API body preservation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

habdelra added 2 commits May 28, 2026 14:22
…nceinstance-error-doc-propagation' into cs-11293-card-response-inherit-error-status
…nceinstance-error-doc-propagation' into cs-11293-card-response-inherit-error-status
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 28, 2026

Host Test Results

    1 files  ±0      1 suites  ±0   1h 48m 9s ⏱️ +49s
2 839 tests ±0  2 824 ✅ ±0  15 💤 ±0  0 ❌ ±0 
2 858 runs  ±0  2 843 ✅ ±0  15 💤 ±0  0 ❌ ±0 

Results for commit 94279f8. ± Comparison against earlier commit 2fd1292.

Realm Server Test Results

    1 files  ±0      1 suites  ±0   11m 59s ⏱️ +37s
1 503 tests ±0  1 503 ✅ ±0  0 💤 ±0  0 ❌ ±0 
1 594 runs  ±0  1 594 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 94279f8. ± Comparison against earlier commit 2fd1292.

habdelra added 2 commits May 28, 2026 15:58
…nceinstance-error-doc-propagation' into cs-11293-card-response-inherit-error-status
@github-actions
Copy link
Copy Markdown
Contributor

Grafana preview

Preview deployed for 1 dashboard in the staging Grafana.
Cross-dashboard drill-throughs still point at the canonical staging dashboards.

Dashboards:

Preview is torn down automatically when this PR is closed or merged.

(Run: https://github.com/cardstack/boxel/actions/runs/26598855997)

@github-actions
Copy link
Copy Markdown
Contributor

Observability diff (vs staging)

Show diff
diff --git a/tmp/remote-canon.X8Sctn/dashboards/boxel-status/service-worker.json b/tmp/committed-canon.3tqdKP/dashboards/boxel-status/service-worker.json
index 14d31ea..cdcc357 100644
--- a/tmp/remote-canon.X8Sctn/dashboards/boxel-status/service-worker.json
+++ b/tmp/committed-canon.3tqdKP/dashboards/boxel-status/service-worker.json
@@ -1811,7 +1811,7 @@
         {
           "hide": 2,
           "name": "env",
-          "query": "staging",
+          "query": "__ENV__",
           "skipUrlSync": true,
           "type": "constant"
         }

(Run: https://github.com/cardstack/boxel/actions/runs/26598855843)

habdelra and others added 3 commits May 28, 2026 17:50
The injected error row never landed: instance rows are keyed by `url`
with the `.json` suffix, while the bare card URL is the `file_alias`, so
`WHERE url = <bare url>` matched nothing and the GET served the card
normally. Match `file_alias` (and scope to the instance row) so the
error flag lands on the row the read resolves.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nceinstance-error-doc-propagation' into cs-11293-card-response-inherit-error-status
…nceinstance-error-doc-propagation' into cs-11293-card-response-inherit-error-status
@habdelra habdelra requested a review from a team May 29, 2026 06:52
@habdelra habdelra changed the base branch from cs-11212-indexer-terminate-instanceinstance-error-doc-propagation to main May 30, 2026 13:14
@habdelra habdelra merged commit 0d1c52e into main May 30, 2026
65 of 66 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants