{"record":{"id":"ac6e0fcbd0a9a58c","repo":"HeyPuter/puter","slug":"not-found-ac6e0f","errorCode":"not_found","errorMessage":"Item not found","messagePattern":"Item not found","errorType":"http","errorClass":"HttpError","httpStatus":404,"severity":"error","filePath":"src/backend/controllers/desktop/DesktopController.js","lineNumber":237,"sourceCode":"     * works for old accounts too).\n     *\n     * Ownership: `entry.user_id === actor.user.id`. Kept as added validation\n     * against bad paths — the previous \"drop user_id entirely\" theory turned\n     * out to be wrong (the actual legacy issue was NULL paths, not user_id\n     * drift), so this filter doesn't lock out old accounts in practice.\n     */\n    async #updateFSEntry(actor, { item_uid, item_path }, patch) {\n        if (!item_uid && !item_path) {\n            throw new HttpError(400, 'Missing `item_uid` or `item_path`', {\n                legacyCode: 'bad_request',\n            });\n        }\n\n        const entry = item_uid\n            ? await this.stores.fsEntry.getEntryByUuid(item_uid)\n            : await this.stores.fsEntry.getEntryByPath(item_path);\n        if (!entry) {\n            throw new HttpError(404, 'Item not found', {\n                legacyCode: 'not_found',\n            });\n        }\n\n        const actorUserId = actor?.user?.id;\n        if (typeof actorUserId !== 'number' || entry.userId !== actorUserId) {\n            throw new HttpError(403, 'Not allowed to update this item', {\n                legacyCode: 'forbidden',\n            });\n        }\n\n        const keys = Object.keys(patch);\n        const setClause = keys.map((k) => `\\`${k}\\` = ?`).join(', ');\n        const values = keys.map((k) => patch[k]);\n\n        await this.db.write(\n            `UPDATE \\`fsentries\\` SET ${setClause} WHERE \\`id\\` = ?`,\n            [...values, entry.id],","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/controllers/desktop/DesktopController.js#L219-L255","documentation":"Thrown by #updateFSEntry when the fsentry lookup (by uid via getEntryByUuid, or by path via getEntryByPath) returns null. The item does not exist, was deleted, or the path/uid is malformed. It is a 404 not_found and fires before the ownership check, so it reveals no ownership information.","triggerScenarios":"POST /set_layout or /set_sort_by with an item_uid that was never created or since deleted, or an item_path that doesn't resolve (typo, wrong root, points into another user's space but doesn't exist).","commonSituations":"Stale uid cached in the GUI after the folder was deleted or moved; path constructed from a user-typed string with a typo; referencing an item from a different account by guessing a path.","solutions":["Re-fetch the item's current uid/path (e.g. via puter.fs.stat / the fsentry listing) before retrying; a deleted item cannot be updated.","Verify the path is absolute and rooted in the actor's own space.","If this recurs for a known-existing item, check the recursive-CTE path fallback isn't disabled and the fsentries row's path/user_id columns aren't NULL."],"exampleFix":"// before\n{ item_uid: staleUid, layout: 'icons' }\n// after\nconst entry = await puter.fs.stat(currentPath);\n{ item_uid: entry.id, layout: 'icons' }","handlingStrategy":"validation","validationCode":"const entry = item_uid\n  ? await fsEntry.getEntryByUuid(item_uid)\n  : await fsEntry.getEntryByPath(item_path);\nif (!entry) throw new NotFoundError('Item not found');","typeGuard":"const exists = <T>(v: T | null | undefined): v is T => v != null;","tryCatchPattern":"try {\n  await setLayout(...);\n} catch (e) {\n  if (isHttpError(e, 404)) { /* re-resolve uid/path or give up */ }\n  else throw e;\n}","preventionTips":["Re-fetch the current uid before retrying after a delete/move.","Confirm path is absolute and inside the user's space.","Treat 404 as terminal for that identifier — don't loop."],"tags":["validation","desktop","not-found","fsentry"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}