{"record":{"id":"f4190cfb5426ae88","repo":"HeyPuter/puter","slug":"bad-request-f4190c","errorCode":"bad_request","errorMessage":"User ID required for puter_output_path","messagePattern":"User ID required for puter_output_path","errorType":"http","errorClass":"HttpError","httpStatus":400,"severity":"error","filePath":"src/backend/drivers/ai-image/ImageGenerationDriver.ts","lineNumber":137,"sourceCode":"    }\n\n    async generate(args: IGenerateParams): Promise<string> {\n        const actor = Context.get('actor') as Actor | undefined;\n        if (!actor)\n            throw new HttpError(401, 'Authentication required', {\n                legacyCode: 'unauthorized',\n            });\n\n        const puterOutputPath = args.puter_output_path;\n        delete args.puter_output_path;\n\n        // Validate the output path early — before spending credits.\n        let resolvedOutputPath: string | undefined;\n        if (puterOutputPath) {\n            const username = actor.user?.username;\n            const userId = actor.user?.id;\n            if (!userId || !username) {\n                throw new HttpError(\n                    400,\n                    'User ID required for puter_output_path',\n                    { legacyCode: 'bad_request' },\n                );\n            }\n            resolvedOutputPath = this.#resolveOutputPath(\n                puterOutputPath,\n                username,\n            );\n            await this.#assertWriteAccess(actor, resolvedOutputPath);\n        }\n\n        let modelId =\n            typeof args.model === 'string'\n                ? args.model.trim().toLowerCase()\n                : undefined;\n        let intendedProvider =\n            args.provider ?? (Context.get('driverName') as string | undefined);","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-image/ImageGenerationDriver.ts#L119-L155","documentation":"When a caller passes puter_output_path (write the result into the user's filesystem), generate() needs actor.user.id and actor.user.username to resolve and write the path. If either is missing it throws HTTP 400 before doing any work. The check exists so credits aren't spent on a generation whose output can't be stored.","triggerScenarios":"An authenticated actor whose user object lacks id or username (partial/anonymous actor, misbuilt auth) supplies puter_output_path; the driver refuses to proceed.","commonSituations":"An auth flow that populates actor but not actor.user; a service account / app user without a username; testing with a stub actor missing user fields.","solutions":["Do not send puter_output_path for actors without a full user (id + username).","Fix the upstream auth so actor.user.id and actor.user.username are always populated for real users.","Omit puter_output_path and handle the returned URL/data-URI yourself if the actor is partial."],"exampleFix":"// before\nawait driver.generate({ prompt, puter_output_path: '/x.png' }); // actor.user incomplete\n// after — only set output path for fully identified users\nconst out = actor?.user?.id && actor?.user?.username\n  ? { puter_output_path: '/x.png' }\n  : {};\nawait driver.generate({ prompt, ...out });","handlingStrategy":"validation","validationCode":"const u = actor?.user;\nconst out = (u?.id && u?.username) ? { puter_output_path } : {};\nawait driver.generate({ prompt, ...out });","typeGuard":"function hasFullUser(actor) {\n  return !!(actor?.user?.id && actor?.user?.username);\n}","tryCatchPattern":null,"preventionTips":["Only set puter_output_path when actor.user.id and actor.user.username are both present.","Fix auth flows so real users always carry id + username.","Omit puter_output_path for partial/service actors."],"tags":["ai-image","validation","filesystem","bad-request"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}