Skip to content

store: refuse oversized filename components before writing - #35

Open
eordano wants to merge 1 commit into
mainfrom
fix/loud-oversized-write
Open

store: refuse oversized filename components before writing#35
eordano wants to merge 1 commit into
mainfrom
fix/loud-oversized-write

Conversation

@eordano

@eordano eordano commented Jul 31, 2026

Copy link
Copy Markdown
Member

Problem

Filename components over NAME_MAX (255 bytes on every supported filesystem) can never be written, but today the attempt fails with the raw filesystem error — ENAMETOOLONG, or os error 3/os error 123 on Windows — surfaced from deep inside a conversion, far from where the doomed name was chosen. Observed on a Windows box while verifying #33:

warn: … deps digest for scene.glb (b64-Qzpc…): local content store: ./abgen-serve-cache\content\3184\b64-Qzpc… : The system cannot find the path specified. (os error 3)

Only unbounded dev-lane ids get this long: b64-<base64 of absolute local path> pseudo-hashes from the sdk-commands preview server pass 255 bytes once the encoded path reaches ~190 characters. Serving-side names in the 200–255 band are already handled by the #33 collapse; names beyond 255 cannot be stored at all, by anyone.

Fix

Names derived through fs_safe_component are already collapsed to a bounded digest. Two writers must keep the incoming name verbatim to preserve its round-trip, and now refuse loudly at the point of intent:

  • LocalContentStore::write — raw content files keyed by cid
  • manifest::write_scene — CLI corpus lane, bundles keyed by served name (all names vetted before anything is written, so a refusal leaves no partial output)

Shared guard: naming::ensure_writable_component with FS_WRITE_COMPONENT_MAX_BYTES = 240 (NAME_MAX minus headroom for the .tmp.{pid}.{seq} suffixes of atomic writes). The error tells the user what to do about it and names the failed name in full — for a b64- pseudo-hash that is the encoded path itself:

Refusing to write into a file whose name will be longer than 255 chars: this will cause problems on some platforms. Try to relocate the folder in a different path, or use smaller folder names. The failed name is: b64-QQQQ…

The JIT lane degrades exactly as before on a refused content download (glb omitted from the manifest, non-zero exitCode) — but the log now states the actual cause.

Testing

  • naming::tests::ensure_writable_component_boundary — 240 passes, 241 refuses with the failed name in the message.
  • local_store::tests::write_refuses_oversized_cid_loudly — oversized cid refused before any directory is created; in-limit cid still writes.
  • manifest::tests::write_scene_refuses_oversized_names_before_writing — oversized entity id and oversized bundle name both refused with no partial output.
  • Full lib suite green: 614 passed, 0 failed.

🤖 Generated with Claude Code

@eordano
eordano force-pushed the fix/loud-oversized-write branch from 8cd4a80 to 143d220 Compare July 31, 2026 16:45
Filename components over NAME_MAX (255 bytes) fail with the raw
filesystem error (ENAMETOOLONG; "os error 3"/"os error 123" on
Windows) from deep inside a conversion, long after the doomed name was
chosen. Only unbounded dev-lane ids get this long: b64-<base64 of a
local path> pseudo-hashes from the sdk-commands preview server pass 255
bytes once the encoded path reaches ~190 characters.

Names derived through fs_safe_component are already collapsed to a
bounded digest, but two writers must keep the incoming name verbatim to
preserve its round-trip: the raw content store (files keyed by cid) and
the CLI corpus lane (bundles keyed by served name). Add a shared guard,
FS_WRITE_COMPONENT_MAX_BYTES = 240 (NAME_MAX minus headroom for the
.tmp.{pid}.{seq} suffixes of atomic writes), and refuse the write up
front with the offending name and its length, before any directory or
sibling file is created.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@eordano
eordano force-pushed the fix/loud-oversized-write branch from 143d220 to bc414cd Compare July 31, 2026 17:45
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.

1 participant