{"record":{"id":"753dfdd93c1a6e22","repo":"HeyPuter/puter","slug":"password-required","errorCode":"password_required","errorMessage":"Password is required.","messagePattern":"Password is required\\.","errorType":"validation","errorClass":"HttpError","httpStatus":400,"severity":"error","filePath":"src/backend/controllers/auth/AuthController.ts","lineNumber":376,"sourceCode":"        // coarser per-IP backstop stops an attacker from minting fresh\n        // fingerprint buckets by rotating client-controlled headers\n        // (User-Agent etc.). Same pattern on the other unauthenticated\n        // credential endpoints below.\n        rateLimit: [\n            { scope: 'login', limit: 10, window: 15 * 60_000 },\n            { scope: 'login-ip', limit: 50, window: 15 * 60_000, key: 'ip' },\n        ],\n    })\n    async handleLogin(req: Request, res: Response): Promise<void> {\n        const { username, email, password } = req.body;\n\n        if (!username && !email) {\n            throw new HttpError(400, 'Username or email is required.', {\n                legacyCode: 'bad_request',\n            });\n        }\n        if (!password || typeof password !== 'string') {\n            throw new HttpError(400, 'Password is required.', {\n                legacyCode: 'password_required',\n            });\n        }\n        if (password.length < (this.config.min_pass_length || 6)) {\n            throw new HttpError(400, 'Invalid password.', {\n                legacyCode: 'bad_request',\n            });\n        }\n\n        // Look up user\n        let user;\n        if (username) {\n            if (typeof username !== 'string')\n                throw new HttpError(400, 'username must be a string.', {\n                    legacyCode: 'bad_request',\n                });\n            user = await this.stores.user.getByUsername(username);\n        } else {","sourceCodeStart":358,"sourceCodeEnd":394,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/controllers/auth/AuthController.ts#L358-L394","documentation":"Returned by POST /login when 'password' is missing or not a string. This is the second validation check — the identifier was accepted but the password field is absent, null, or a non-string type. Its legacy code 'password_required' distinguishes it from the short-password 'Invalid password.' check that follows.","triggerScenarios":"Submitting a login form before the password is entered; sending password as null, a number, or an object; a serialization bug that drops the field.","commonSituations":"Empty password field; client that hashes the password into a non-string field; test fixture omitting the field.","solutions":["Ensure a non-empty string 'password' is present in the JSON body.","Validate client-side that the password field has a string value before submit.","Check that the request body is parsed as JSON (Content-Type: application/json)."],"exampleFix":"// before\nawait fetch('/login', { method:'POST', body:JSON.stringify({ username }) });\n\n// after\nawait fetch('/login', { method:'POST', body:JSON.stringify({ username, password: String(pwd) }) });","handlingStrategy":"validation","validationCode":"if (typeof body.password !== 'string' || body.password.length === 0) {\n  throw new Error('Password is required.');\n}","typeGuard":"/** @returns {p is string} */\nfunction isNonEmptyString(p) { return typeof p === 'string' && p.length > 0; }","tryCatchPattern":null,"preventionTips":["Coerce the password to a string before sending.","Validate non-empty client-side to give a clearer message than the server's."],"tags":["auth","login","validation","password","bad-request"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}