{"record":{"id":"319198313a051fad","repo":"HeyPuter/puter","slug":"not-found-319198","errorCode":"not_found","errorMessage":"Entry not found: ${raw}","messagePattern":"Entry not found: (.+?)","errorType":"http","errorClass":"HttpError","httpStatus":404,"severity":"error","filePath":"src/backend/controllers/fs/legacyFsHelpers.ts","lineNumber":113,"sourceCode":"// expansion via its own `#normalizePath` helper.\nexport async function resolveV1Selector(\n    fsEntryStore: FSEntryStore,\n    raw: unknown,\n): Promise<FSEntry> {\n    const username = Context.get('actor')?.user?.username;\n\n    // String shorthand — either an absolute path (`/a/b/c`) or a UUID.\n    // The legacy API accepts both interchangeably; dispatch on the leading\n    // character rather than guessing by regex. Anything that doesn't start\n    // with `/` is treated as a uid. Tilde-rooted paths are path-shaped.\n    if (typeof raw === 'string') {\n        const isPath = raw.startsWith('/') || raw.startsWith('~');\n        const ref = isPath\n            ? { path: expandTildePath(raw, username) }\n            : { uid: raw };\n        const entry = await resolveNode(fsEntryStore, ref, { required: true });\n        if (!entry)\n            throw new HttpError(404, `Entry not found: ${raw}`, {\n                legacyCode: 'not_found',\n            });\n        return entry;\n    }\n\n    const record = asRecord(raw);\n\n    // {parent, name}: \"child selector\" — resolve parent, then child by name.\n    if (record.parent !== undefined && typeof record.name === 'string') {\n        const parent = await resolveV1Selector(fsEntryStore, record.parent);\n        const childPath = joinChildPath(parent.path, record.name);\n        const child = await resolveNode(\n            fsEntryStore,\n            { path: childPath },\n            { required: true },\n        );\n        if (!child)\n            throw new HttpError(404, `Entry not found: ${childPath}`, {","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/controllers/fs/legacyFsHelpers.ts#L95-L131","documentation":"In `resolveV1Selector`, a plain-string selector is treated as a path (leading `/` or `~`) or a UID (anything else) and resolved via `resolveNode` with `required: true`. If resolution returns nothing, the helper throws 404 (`not_found`) echoing the raw input. This is the v1 'entry not found' for string refs.","triggerScenarios":"Passing a UID that doesn't exist, a path with a typo, or a path inside a folder that was deleted/moved. The raw string is interpolated into the message for debugging.","commonSituations":"Client cached a UID after the entry was deleted; wrong path casing or trailing slash; referring to another user's private path; race where the entry is removed between list and operation.","solutions":["Verify the UID/path exists (stat) before using it as a selector.","Refresh cached UIDs when a 404 is returned, since the entry may have been deleted.","Double-check path spelling, casing, and leading slash."],"exampleFix":"// before\nawait puter.fs.read({ uid: staleUid }); // entry was deleted\n\n// after\nlet entry;\ntry { entry = await puter.fs.stat({ uid }); }\ncatch { entry = await puter.fs.stat('/path/to/file'); }\nawait puter.fs.read(entry.uid);","handlingStrategy":"try-catch","validationCode":"async function entryExists(stat, ref) { try { await stat(ref); return true; } catch { return false; } }","typeGuard":"function isStringSelector(v) { return typeof v === 'string' && v.length > 0; }","tryCatchPattern":"try { return await resolve(ref); }\ncatch (e) { if (e.status === 404) { ref = await refreshRef(); return await resolve(ref); } throw e; }","preventionTips":["Stat before operating on a cached ref.","Refresh UIDs on 404; the entry may be gone.","Verify path casing and leading slash."],"tags":["filesystem","not-found","selector","v1-api"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}