{"record":{"id":"b19f73a92ca81b02","repo":"openai/codex","slug":"api-key-must-be-provided-via-stdin-e-g-printenv","errorCode":null,"errorMessage":"API key must be provided via stdin (e.g. printenv OPENAI_API_KEY | codex responses-api-proxy)","messagePattern":"API key must be provided via stdin \\(e\\.g\\. printenv OPENAI_API_KEY \\| codex responses-api-proxy\\)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"codex-rs/responses-api-proxy/src/read_api_key.rs","lineNumber":135,"sourceCode":"        // Continue loop; if buffer fills without newline/EOF we'll error below.\n    }\n\n    // If buffer filled and we did not see newline or EOF, error out.\n    if total_read == capacity && !saw_newline && !saw_eof {\n        buf.zeroize();\n        return Err(anyhow!(\n            \"API key is too large to fit in the {BUFFER_SIZE}-byte buffer\"\n        ));\n    }\n\n    let mut total = prefix_len + total_read;\n    while total > prefix_len && (buf[total - 1] == b'\\n' || buf[total - 1] == b'\\r') {\n        total -= 1;\n    }\n\n    if total == AUTH_HEADER_PREFIX.len() {\n        buf.zeroize();\n        return Err(anyhow!(\n            \"API key must be provided via stdin (e.g. printenv OPENAI_API_KEY | codex responses-api-proxy)\"\n        ));\n    }\n\n    if let Err(err) = validate_auth_header_bytes(&buf[AUTH_HEADER_PREFIX.len()..total]) {\n        buf.zeroize();\n        return Err(err);\n    }\n\n    let header_str = match std::str::from_utf8(&buf[..total]) {\n        Ok(value) => value,\n        Err(err) => {\n            // In theory, validate_auth_header_bytes() should have caught\n            // any invalid UTF-8 sequences, but just in case...\n            buf.zeroize();\n            return Err(err).context(\"reading Authorization header from stdin as UTF-8\");\n        }\n    };","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/responses-api-proxy/src/read_api_key.rs#L117-L153","documentation":"After reading stdin and trimming trailing CR/LF, if nothing remains beyond the 'Bearer ' prefix the key is empty and read_auth_header_with fails with this hint. Both an immediate EOF (empty stdin) and newline/whitespace-only input trigger it.","triggerScenarios":"Running 'codex responses-api-proxy' without piping anything (stdin already at EOF - common in cron, CI, or detached sessions), piping an unset variable, or piping only blank lines.","commonSituations":"Forgetting the pipe in scripts; OPENAI_API_KEY unset so printenv emits nothing; CI steps with stdin closed to /dev/null; running under nohup without stdin redirection.","solutions":["Pipe the key explicitly: printenv OPENAI_API_KEY | codex responses-api-proxy --upstream-url ...","Verify the variable first: test -n \"$OPENAI_API_KEY\" || exit 1","In CI, export the secret before the step that launches the proxy"],"exampleFix":"# before: stdin empty/EOF\ncodex responses-api-proxy --upstream-url http://localhost:3000\n# after\nprintenv OPENAI_API_KEY | codex responses-api-proxy --upstream-url http://localhost:3000","handlingStrategy":"validation","validationCode":"if [ -z \"${OPENAI_API_KEY:-}\" ]; then echo 'OPENAI_API_KEY not set or empty' >&2; exit 1; fi\nprintenv OPENAI_API_KEY | codex responses-api-proxy \"$@\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Fail fast on empty secrets in wrapper scripts","Never rely on implicit stdin in cron/CI - always pipe","Document the stdin contract in runbooks"],"tags":["rust","stdin","api-key","missing-credentials"],"backgroundTag":"missing-api-key","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}