Skip to content

fix(cli): distinguish an unenrolled project from a missing one on the compute routes - #6645

Merged
johnstonmatt merged 4 commits into
developfrom
FUNC-897/better-error-message-compute-unenrolled
Sep 18, 2026
Merged

johnstonmatt merged 4 commits into
developfrom
FUNC-897/better-error-message-compute-unenrolled

Conversation

@johnstonmatt

@johnstonmatt johnstonmatt commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Depends on https://github.com/supabase/platform/pull/38464

The Management API answers 404 on the compute routes for several distinct conditions, and the CLI was collapsing them into the wrong message:

  • A project outside the private alpha was told No project <ref> was found for this account on the collection routes, and "<name>" is not deployed on status and delete — sending someone to re-link or re-push a project that was never the problem.
  • A route this CLI build asks for but the API does not serve was reported the same two ways.
  • A project that does not exist was told "<name>" is not deployed on status, and delete reported removing it.

Each condition carries its own error.code, so each now gets its own error, on every route including the named-compute status and delete ones:

condition code error
project outside the alpha not_found.compute.not_enabled ComputeUnavailableError, pointing at the public alpha rather than asking the reader to seek enrolment
no such route not_found, with the router's Cannot GET /… message ComputeRouteNotFoundError, naming the route
no such project not_found ComputeProjectNotFoundError, which now means only what it says
no compute under that name not_found.compute.instance ComputeNotDeployedError, the only one the named routes can mean

The poll behind push no longer retries the three permanent verdicts for its full 30-second window, and the analytics logs route — which is not gated on the alpha's allow-list — classifies its own 404 body instead of blaming the alpha for every one.

Also extracts bodyText, unexpectedStatus(operation, response), decodeJsonBody and the 404 body reader in compute-api-status.ts so compute-api.ts and compute-logs-api.ts share one place to read a response body, instead of threading status and body through every call site.

The enrolment split depends on the Management API emitting not_found.compute.not_enabled, which is not deployed yet. Until it is, an unenrolled project answers a bare generic_not_found, which no branch claims and which falls back to the alpha refusal — so the enrolment message is already right, and only its precision waits on the API. FUNC-897 should stay open until the API side is live.

https://linear.app/supabase/issue/FUNC-897/fix-no-project-ref-was-found-for-unenrolled-compute-projects

Both compute-api.ts and compute-logs-api.ts repeated the same read-body-as-text-or-empty and
json-then-decode sequences; pull them into bodyText and decodeJsonBody so the upcoming 404
classification work has one place to read a response's body from.
The Management API answers 404 with the same not_found code for three unrelated conditions: no
such project, no such route, and (on the named-compute routes) an undeployed compute. Callers
read all of these as either "missing project" or "not deployed", so a route the CLI's own version
has fallen behind on was misreported as "no project ref was found", sending someone to re-link a
project that was never the problem.

Add ComputeRouteNotFoundError and recognize the router's own "Cannot GET /..." body so a 404 from
an unserved route is named for what it is, on both the collection endpoints and the named-compute
get/delete routes.
`status` and `delete` read every 404 the compute route answered as "not
deployed", so a project outside the alpha was told its compute was missing.
Branch on the `not_found.compute.not_enabled` code the API now carries, on
both route families, and point at the public alpha rather than at enrolment.
@johnstonmatt
johnstonmatt requested a review from a team as a code owner September 16, 2026 04:12

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 AI Review

The named-compute 404 handling has a major confirmed bug: missing projects are still treated as undeployed computes or successful deletes. Most other confirmed findings are stale documentation, overly broad retry/classification behavior, and outdated test fixtures. One proposed router-body robustness issue remains uncertain because the checked-in code documents and tests only the structured envelope.

Findings

Severity Location Category Sources Claim
🟠 MAJOR apps/cli/src/shared/compute/compute-api.ts:182 error-handling codex Named GET and DELETE requests treat a nonexistent project as an absent compute or successful deletion instead of raising ComputeProjectNotFoundError.
🟡 MINOR apps/cli/src/shared/compute/compute-api.ts:339 documentation claude The deleteCompute comment incorrectly describes every 404 as an already-completed delete even though two classified 404 bodies now fail.
🟡 MINOR apps/cli/src/shared/compute/compute-api.ts:112 error-handling claude Router-404 recognition fails when the router message is not accompanied by the expected error envelope and code, causing fallback misclassification.
🟡 MINOR apps/cli/src/shared/compute/compute-api.ts:388 error-handling claude awaitComputeBuild retries the newly introduced permanent route-not-found and unavailable failures for up to 30 seconds before surfacing them.
🟡 MINOR apps/cli/src/shared/compute/compute.errors.ts:208 documentation claude ComputeUnavailableError's comment incorrectly says the error is raised only on collection endpoints, although named GET and DELETE routes now raise it too.
🟡 MINOR apps/cli/src/commands/experimental/compute/delete/SIDE_EFFECTS.md:59 documentation claude The delete exit-code contract incorrectly says every DELETE 404 succeeds, although router and not-enrolled 404 responses now fail.
🟡 MINOR apps/cli/src/commands/experimental/compute/delete/delete.handler.ts:70 documentation claude The preflight GET is described broadly as a courtesy rather than a prerequisite, but an unrouted GET aborts deletion before DELETE is attempted.
⚪ NIT apps/cli/src/shared/compute/compute-logs-api.ts:159 consistency claude fetchComputeLogs maps every 404 to ComputeUnavailableError, including 404s caused by a missing project or unserved logs route.
⚪ NIT apps/cli/src/commands/experimental/compute/push/push.integration.test.ts:1035 test-coverage claude The push enrollment test still uses generic_not_found, so it exercises only the unrecognized-body fallback rather than the new not-enrolled code.
⚪ NIT apps/cli/src/commands/experimental/compute/list/list.integration.test.ts:341 test-coverage codex The older list enrollment test still uses generic_not_found and now redundantly exercises the fallback instead of the explicit enrollment-code branch.

Findings outside the diff

  • 🟡 MINOR apps/cli/src/shared/compute/compute.errors.ts:208 — ComputeUnavailableError's comment incorrectly says the error is raised only on collection endpoints, although named GET and DELETE routes now raise it too.
  • 🟡 MINOR apps/cli/src/commands/experimental/compute/delete/SIDE_EFFECTS.md:59 — The delete exit-code contract incorrectly says every DELETE 404 succeeds, although router and not-enrolled 404 responses now fail.
  • 🟡 MINOR apps/cli/src/commands/experimental/compute/delete/delete.handler.ts:70 — The preflight GET is described broadly as a courtesy rather than a prerequisite, but an unrouted GET aborts deletion before DELETE is attempted.
  • ⚪ NIT apps/cli/src/commands/experimental/compute/push/push.integration.test.ts:1035 — The push enrollment test still uses generic_not_found, so it exercises only the unrecognized-body fallback rather than the new not-enrolled code.
  • ⚪ NIT apps/cli/src/commands/experimental/compute/list/list.integration.test.ts:341 — The older list enrollment test still uses generic_not_found and now redundantly exercises the fallback instead of the explicit enrollment-code branch.

Stats

Claude findings: 8 · Codex findings: 1 · Confirmed: 9 · Refuted: 0 · Uncertain: 1


Models: claude-opus-5 + gpt-5.6-sol · Trigger: auto · Workflow run

This review runs once per PR. A maintainer can request another with a /ai-review comment.

Comment thread apps/cli/src/shared/compute/compute-api.ts Outdated
Comment thread apps/cli/src/shared/compute/compute-api.ts Outdated
Comment thread apps/cli/src/shared/compute/compute-logs-api.ts
Comment thread apps/cli/src/shared/compute/compute-api.ts
Comment thread apps/cli/src/shared/compute/compute-api.ts Outdated
…med routes

`not_found.compute.instance` is the code an absent compute answers with, so a
plain `not_found` on `GET`/`DELETE /compute/{name}` is a missing project and
now reports as one instead of "not deployed" or a delete that happened.

The poll behind `push` stops retrying the verdicts a retry cannot change, the
logs 404 classifies its own body rather than blaming the alpha for every one,
and the 404 body reader moves next to the other shared response helpers.
@johnstonmatt

Copy link
Copy Markdown
Contributor Author

Review findings addressed in 7fc9f66. The five that landed outside the diff:

  • compute.errors.ts:208ComputeUnavailableError's doc no longer claims collection endpoints only; it names not_found.compute.not_enabled and says it is raised on every route plus as the unclassifiable-body fallback.
  • delete/SIDE_EFFECTS.md:59 — the 0 row now reads "a 404 on DELETE that names no other condition", and the 1 row lists the missing project and unserved route alongside the alpha refusal.
  • delete/delete.handler.ts:70 — the comment now separates the two: a refused read is still not a prerequisite, but a read that cannot reach compute at all aborts before any DELETE is sent.
  • push.integration.test.ts — added a test for the explicit not_found.compute.not_enabled code; the generic_not_found one is retitled to say what it actually pins, the pre-rollout body the deployed API still sends.
  • list.integration.test.ts — same retitling; it sits next to the existing explicit-code test rather than duplicating it.

Also confirmed from project-workers.ts that an absent compute answers not_found.compute.instance, which is what let the named routes tell a missing project apart from an undeployed one.

@johnstonmatt
johnstonmatt added this pull request to the merge queue Sep 18, 2026
Merged via the queue into develop with commit c0fcf87 Sep 18, 2026
72 checks passed
@johnstonmatt
johnstonmatt deleted the FUNC-897/better-error-message-compute-unenrolled branch September 18, 2026 07:42
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.

2 participants