{"record":{"id":"d7b6073ce0dd0a7c","repo":"HeyPuter/puter","slug":"bad-request-d7b607","errorCode":"bad_request","errorMessage":"Missing or invalid `name` query param","messagePattern":"Missing or invalid `name` query param","errorType":"validation","errorClass":"HttpError","httpStatus":400,"severity":"error","filePath":"src/backend/controllers/apps/AppController.js","lineNumber":175,"sourceCode":"        router.get(\n            '/apps/nameAvailable',\n            {\n                subdomain: 'api',\n                requireAuth: true,\n                // Answers \"does this name exist?\" for any name, so it is a\n                // name-enumeration oracle however cheap it is to serve.\n                // Mirrors the `isNameAvailable` budget on AppDriver.\n                rateLimit: {\n                    scope: 'app-name-available',\n                    limit: 60,\n                    window: 60_000,\n                    key: 'user',\n                },\n            },\n            async (req, res) => {\n                const name = req.query?.name;\n                if (!name || typeof name !== 'string') {\n                    throw new HttpError(\n                        400,\n                        'Missing or invalid `name` query param',\n                        { legacyCode: 'bad_request' },\n                    );\n                }\n                const available = await this.appDriver.isNameAvailable(name);\n                res.json({ name, available });\n            },\n        );\n\n        // POST /rao — record a recent app open. When an app-under-user\n        // actor calls this, the app id is already on the token — clients\n        // don't re-send it in the body. Fall back to `actor.app.uid`\n        // before 400-ing for a missing body field.\n        //\n        // Authorization: only two callers are trusted to report opens —\n        //   1. a root user actor (plain session, no `.app` and no access\n        //      token), e.g. the GUI launching apps on behalf of the user;","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/controllers/apps/AppController.js#L157-L193","documentation":"AppDriver.select enforces a single pagination mode per request. If args.cursor decodes to a payload AND args.offset is also defined, it throws 400 bad_request. Mixing cursor- and offset-based pagination is ambiguous (cursor already encodes position), so the driver refuses rather than guessing which wins. See doc/pagination.md for the one convention.","triggerScenarios":"Calling puter.apps.list() / the driver select() with both `cursor` (from a previous page) and `offset` set in the same request — e.g. a UI that held an offset default while also forwarding the server's cursor.","commonSituations":"Client merged a cursor-based 'next page' flow with a legacy offset-based default; query-param builder always includes offset=0; refactor left an offset field populated alongside the cursor.","solutions":["Send exactly one of cursor or offset — never both.","For 'next page', pass only the cursor returned by the previous response and drop offset.","Reset offset to undefined when adopting cursor pagination in the client.","Validate the params object before submit: assert !(cursor && offset != null)."],"exampleFix":"// before\nawait puter.apps.list({ cursor: prevCursor, offset: 0, limit: 50 });\n\n// after — pick one pagination mode\nawait puter.apps.list({ cursor: prevCursor, limit: 50 });\n// or\nawait puter.apps.list({ offset: 100, limit: 50 });","handlingStrategy":"validation","validationCode":"function assertOnePager(args) {\n  if (args.cursor != null && args.offset != null) {\n    throw new Error('cursor and offset cannot be combined');\n  }\n}\nassertOnePager(params);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pick one pagination mode (cursor OR offset) per list flow and reset the other to undefined.","For 'next page', forward only the server-returned cursor and drop any default offset.","See doc/pagination.md for the single convention used across list APIs."],"tags":["apps","pagination","validation","cursor"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}