{"record":{"id":"9f77b2fa66fee782","repo":"HeyPuter/puter","slug":"unauthorized-9f77b2","errorCode":"unauthorized","errorMessage":"Authentication required","messagePattern":"Authentication required","errorType":"http","errorClass":"HttpError","httpStatus":401,"severity":"critical","filePath":"src/backend/drivers/apps/AppDriver.js","lineNumber":767,"sourceCode":"                // Malformed config value — nothing to reserve from it.\n            }\n        }\n\n        if (reserved.has(hostname)) {\n            throw new HttpError(\n                400,\n                '`index_url` cannot point at a Puter system host',\n                { legacyCode: 'bad_request' },\n            );\n        }\n    }\n\n    // -- Permission checks --------------------------------------------\n\n    #requireActor() {\n        const actor = Context.get('actor');\n        if (!actor)\n            throw new HttpError(401, 'Authentication required', {\n                legacyCode: 'unauthorized',\n            });\n        return actor;\n    }\n\n    #requireUserOrAppActor(actor) {\n        if (!actor.user)\n            throw new HttpError(403, 'User actor required', {\n                legacyCode: 'forbidden',\n            });\n    }\n\n    async #resolve({ uid, id }) {\n        if (uid) return this.#getByUidWithAlias(uid);\n        if (id?.uid) return this.#getByUidWithAlias(id.uid);\n        if (id?.name) return this.appStore.getByName(id.name);\n        if (id?.id) return this.appStore.getById(id.id);\n        if (typeof id === 'number') return this.appStore.getById(id);","sourceCodeStart":749,"sourceCodeEnd":785,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/apps/AppDriver.js#L749-L785","documentation":"Thrown by `#requireActor` when the ALS `Context` has no `actor` set — i.e. the request reached the driver without a resolved, authenticated actor. This is a precondition guard called at the start of every mutating app operation. Returns HTTP 401 with legacyCode `unauthorized`.","triggerScenarios":"Calling an app driver method (create/update/delete/upsert) in a code path where `Context.get('actor')` is unset: an unauthenticated request, a background job that forgot to set actor context, or a misconfigured route missing the auth gate.","commonSituations":"A controller/route missing the `auth` RouteOption so the request is anonymous by the time it hits the driver; an extension calling the driver directly without establishing actor context; tests that bypass middleware.","solutions":["Ensure the calling route carries the auth gate (`RouteOptions` auth) so actor context is populated.","In background/internal callers, set the actor in Context before invoking the driver.","Authenticate the request (send a valid token) before retrying."],"exampleFix":"// before\nrouter.post('/apps/update', (req, res) => driver.update({...req.body}));\n\n// after\nrouter.post('/apps/update', { auth: true }, (req, res) => driver.update({...req.body}));","handlingStrategy":"validation","validationCode":"// This is an auth-context precondition; validate the request is authenticated\nif (!req.user && !req.session) return res.status(401).send('auth required');\n// and ensure the route has the auth gate so Context.actor is set","typeGuard":null,"tryCatchPattern":"try {\n  await driver.update({ uid, object });\n} catch (e) {\n  if (e.code === 'unauthorized') { /* redirect to login */ return; }\n  throw e;\n}","preventionTips":["Always attach the auth RouteOption to routes that call app driver mutations.","Set actor in Context for internal/background callers before invoking the driver.","Authenticate the client before allowing the call."],"tags":["apps","auth","unauthorized","driver"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}