Skip to content

GET /api/v1/packages/:id swallows the same failed REGISTRY read — and answers a terminal 404 RESOURCE_NOT_FOUND for it #11376

Description

@os-zhuang

Found while implementing #11130 (the list door's registry half). Not fixed there — that card's dispatch ruling scoped the edit to the GET /api/v1/packages handler by name. Filed unassigned for triage.

The defect

packages/rest/src/package-routes.ts, the GET /api/v1/packages/:id handler, tries the durable read first and falls back to the registry:

// Fall back to registry (in-memory loaded packages)if(options.protocol&&typeofoptions.protocol.getMetaItems==='function'){try{constresult=awaitoptions.protocol.getMetaItems({type: 'package'});constmatch=result?.items?.find((item: any)=>(item.manifest?.id||item.id)===packageId);if(match){sendOk(res,{package: { ...match,source: 'registry'}});return;}}catch{// Protocol unavailable}}sendError(res,404,'RESOURCE_NOT_FOUND',`Package "${packageId}" was not found.`);

When getMetaItems throws, the catch absorbs it and control falls straight through to the line below. The door then answers 404 RESOURCE_NOT_FOUNDPackage "<id>" was not found.

Same standing family ruling as its siblings — #10965 · #10677 / PR #10788 · #10789 / PR #10964 · #11063 · #11130: a read that could not happen must not be reported as a read that found nothing.

Why this is the worse half, not a smaller one

The list door's version (#11130) answered a 200 with a total that under-counted. This one answers a terminal negative fact: 404 / RESOURCE_NOT_FOUND is not "the listing may be short", it is "this package does not exist". A caller acts on it — an installer decides the package is not installed and offers to install it; a console hides the entry; a script branches to the create path. The producer's own words for this condition are the opposite: "whether this item exists is unknown".

It is also the exact defect #5532 fixed one layer down, resurfacing one layer up. ObjectStackProtocolImplementation.getMetaItems was taught not to report an unreadable sys_metadata as "that item does not exist"; this consumer-side catch then re-applies precisely that relabelling to the protocol's answer.

The producer already declares the refusal

Measured on the live implementation while working #11130. The protocol service this registrar is handed is ObjectStackProtocolImplementation (packages/metadata-protocol/src/plugin.ts registers it; rest-api-plugin.ts resolves it and direct-mount-composition.ts passes it through). Its getMetaItems routes every non-benign sys_metadata overlay read failure through rethrowUnlessMetadataStoreUnprovisionedmetadataStoreUnavailableError: SERVICE_UNAVAILABLE / 503 with an ADR-0112 status+code on the error (#5532).

Driven with this door's own request:

outage (ECONNREFUSED) type=package => THREW status=503 code=SERVICE_UNAVAILABLE
msg="The metadata store could not be read, so whether
this item exists is unknown. …"
healthy store type=package => RESOLVED {"type":"package","items":[]}
no such table (1st boot) type=package => RESOLVED {"type":"package","items":[]}

So there is a declared envelope here waiting to be let through, and removing the catch is mechanical — the same edit #11063 made for the durable half and #11130 made for the list door's registry half. sendThrownError already carries the producer's status and code.

Worth stating: the in-tree comment currently overclaims

The [#11063] note beside the durable read asserts:

GET /packages/:id next door has never had an inner catch, so it has answered that same 503 since #10965.

True of that door's durable read. Its registry read is the block quoted above. Whichever way this is triaged, that sentence wants a qualifier.

Not measured here

  • Whether a caller depends on the 404. The behaviour change is narrower than the list door's (it only moves the answer on a failed read, never on a genuine miss), but the 404 → 503 flip on this route was not surveyed against consumers.
  • The DELETE /api/v1/packages/:id handler was not read for this shape.

Refs

#11130 · #11063 · #10965 · #5532 · #10677 / PR #10788 · #10789 / PR #10964 · ADR-0112

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions