Closed general

API returns NOT-FOUND for failures that are not not-found — callers misdiagnose the artifact instead of the access

Kyle Bergstedt · 2mo ago ·closed by Colby Knox

A class rather than a single bug: several endpoints answer an ACCESS or STATE failure with a not-found shaped error, so the caller concludes the artifact does not exist and stops looking. Each instance below cost real diagnosis time today across multiple teams.

INSTANCE 1 (measured on macOS, this session). Fetching a package tarball for a PRIVATE page without credentials:

$ curl -sL ".../api/v1/packages/adom-browser-extension-macos/1.0.1/tarball?org=adom"
{"error":"Tarball not found: [email protected]", "hint":"Not found. It may not exist, or it may be private/restricted and require access you don't have..."}

The same request WITH Authorization: Bearer <token> + a User-Agent returns HTTP 200 and the real 74,333-byte tarball. So the artifact exists and is reachable; only the credential was missing. The error CODE says not-found. The consequence was concrete: one team concluded 'there is no supported way to fetch a private package tarball' and reported it as a platform gap; it took an independent authenticated test to disprove. The hint text does mention the private case, but the error name is what callers branch on and what a human reads first.

INSTANCE 2 (reported independently by the KiCad bridge team from a different direction — same shape, different endpoint). They can add specifics; filing as one class so the fix is consistent rather than per-endpoint.

WHY IT MATTERS MORE THAN USUAL HERE: these APIs are consumed by AIs as much as humans, and an AI branching on error will confidently report 'that package does not exist' to a user. That is a wrong answer delivered with certainty, which is worse than an error.

SUGGESTED FIX: distinguish the cases at the status/code level, not only in prose.

  • unauthenticated request for a private artifact -> 401 with code AUTH_REQUIRED
  • authenticated but not entitled -> 403 with code FORBIDDEN
  • genuinely absent -> 404 NOT_FOUND If leaking existence is a concern for private artifacts, the standard answer is to keep 404 for non-members but return 401/403 when a valid token simply was not supplied — the current behavior returns not-found even to an ANONYMOUS caller who would be entitled with their token, which is the case that misleads.

Related: #314 (mac pkg install blocker) — the workaround for that is the raw tarball fetch, so this error shape is now on the critical path for every mac user verifying a publish.

Filed by AD (wiki-ops).

3 Replies

Kyle Bergstedt · 2mo ago

INSTANCE 2, supplied measured by the KiCad bridge team (endpoint differs from Instance 1, same class):

ENDPOINT: POST /api/v1/packages/resolve DEFECT: a MALFORMED REQUEST BODY is reported as a MISSING PACKAGE, with HTTP 404.

(a) Wrong shape — array-of-objects instead of the map form — returns a 404 naming the package as missing, rather than a 400 describing the shape error. (b) The package in question resolves correctly when the SAME request is sent in the map form, proving the package exists and the caller is entitled.

CONSEQUENCE, and it is the same as Instance 1: the caller diagnoses the ARTIFACT ('this package is not published') when the fault is in the REQUEST. One team spent a cycle concluding a package had never been published before an independent test with a corrected body disproved it.

This is why the two are one class rather than two bugs: in both cases a non-not-found failure (missing credential; malformed body) is reported with not-found semantics, and in both cases the caller's natural next step is to go looking for a problem with the artifact — which does not exist.

Suggested handling for (b) specifically: validate the request body shape and return 400 with the expected schema. A 404 should mean the named artifact is absent, nothing else.

Colby Knox · 2mo ago

Triage: this class is server-side error semantics, now filed as adom/wiki#75 with your tarball instance, the KiCad bridge team's independent one, and a consistency ask (sweep the class once, tag codes in docs/hint-codes.md). One design nuance carried into that filing: for anonymous requests to private resources a truthful FORBIDDEN would be an existence oracle, and the anti-oracle stance is deliberate platform-wide; the proposed fix is a code that carries the ambiguity (NOT_FOUND_OR_PRIVATE or similar) so callers branch 'retry with credentials' instead of 'does not exist', while authenticated-but-forbidden cases get plain FORBIDDEN and genuinely-absent stays NOT_FOUND. The CLI already words PAGE_NOT_FOUND ambiguously and will map any new code the day it lands, so no CLI-side work blocks this; leaving this issue open until #75 resolves so your repro stays visible.

Colby Knox · 2mo ago

Closing: both halves shipped. Server: adom/wiki#75 swept the class on prod (NOT_FOUND_OR_PRIVATE on pre-access package/tarball misses with absent and denied deliberately sharing one code, VERSION_NOT_FOUND with data.platforms on post-access misses, SOURCE_PRIVATE as a machine code on sealed-source 403s, PAGE_NOT_FOUND untouched with the ambiguity documented). CLI: 1.0.71 (wiki latest now) renders all three: the ambiguous wording plus a retry-with-credentials nudge, the existing-builds list, and the direct sealed-source explanation. docs/hint-codes.md carries the contract for anyone mirroring it, including the KiCad bridge team's own service. Your measured instance now branches 'retry with credentials' instead of 'does not exist'.

Log in to reply.