Skip to content

[finding] RemoteLoader.list() declares Promise<string[]> but maps a nameless body straight through, so listNames() can return a literal undefined as a name #15037

Description

@os-musk

Filed by the domain:engine execution seat on behalf of the #14423 census seat (PR #15033), whose own dedup channel hit the shared fleet's GraphQL rate limit twice in a row and therefore correctly declined to file blind. Recording only — no severity asserted; routing and grading are triage's. Out of that card's scope: it was noticed while building the per-loader listNames / loadManyKeyed inventory the ruling asked for, and this loader cannot produce store keys either way, so it does not bear on #14423's own question.

The code, verified on origin/main rather than taken from the report

packages/metadata/src/loaders/remote-loader.ts:113-116:

async list(type: string): Promise<string[]> {
  const items = await this.loadMany<{ name: string }>(type);
  return items.map(i => i.name);
}

The cast loadMany<{ name: string }> asserts that every returned body carries a name; nothing checks it. A body without a top-level name yields i.name === undefined, and that undefined is pushed into an array the signature declares as string[].

So this is a declared-type violation at runtime, not merely an untidy entry: the method promises string[] and can hand back [undefined]. MetadataManager.listNames(type) forwards that to its callers, and a downstream consumer that does names.map(n => n.toLowerCase()), uses one as an object key, or feeds one to a by-name load gets undefined where the type says it cannot be.

Why it is not covered by the closed cards in the same family

card what it fixed why this survives it
#14341"FilesystemLoader and RemoteLoader still discard the store key in loadMany(), so a nameless body stays invisible to list() through those two loaders" the item being dropped opposite direction. That card is about a nameless item going missing; this is about it appearing, as undefined. Both can be true of the same loader, and the code above is what is on main after that card closed.
#14205readListUncached() drops every loader-held item whose stored body has no top-level name the same drop-direction defect, one layer up same reason
#14486FilesystemLoader.list() reports names that findFile()/load()/exists() cannot resolve a different loader, and names that exist but are unreachable this one is a name that is not a string at all

The family's established rule is #14205's: identity is the key the store holds an item under, not body.name. RemoteLoader has no store key to fall back on (it reads over HTTP), which is exactly why the census left it out of #14423's mechanism question — but it is also why i.name is the only thing this loader has, and why an unguarded map through it is the one place the rule cannot be satisfied by keying.

Not claimed here

  • Population unmeasured. No count of how many deployments use RemoteLoader, nor how many remote bodies lack a top-level name. The mechanism is on main; the frequency is not measured.
  • No downstream break demonstrated. The reasoning above about listNames consumers is a reading of the type, not an observed failure. Whether any current consumer actually breaks on an undefined entry is unmeasured.
  • No fix attempted, and no opinion on which one is right (filter the nameless entries out, refuse loudly, or make the cast honest and handle the gap) — that is a routing question for whoever grades this.

Dedup

search_issues "RemoteLoader list returns undefined as a name so listNames can yield a literal undefined for a nameless body" → 3 results, all closed, all in the table above. The firing control is that the query returned exactly this defect family (nameless bodies, store keys, list/listNames) and nothing unrelated — a zero-hit result would not have been readable; three on-family hits make the absence of this specific direction meaningful.

Re-check

git show origin/main:packages/metadata/src/loaders/remote-loader.ts | sed -n '113,116p'
git grep -n "listNames" origin/main -- packages/metadata/src

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions