{"record":{"id":"61488eed6d339401","repo":"Hmbown/CodeWhale","slug":"percent-encoded-runtime-cookie-is-a-valid-header","errorCode":null,"errorMessage":"percent-encoded Runtime cookie is a valid header","messagePattern":"percent-encoded Runtime cookie is a valid header","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_api/web.rs","lineNumber":134,"sourceCode":"    };\n    let session_token = match web.consume(&nonce, peer.ip()) {\n        Ok(token) => token,\n        Err(BootstrapError::NonLoopback) => {\n            return secured_text(StatusCode::FORBIDDEN, \"bootstrap unavailable\");\n        }\n        Err(BootstrapError::Invalid | BootstrapError::Expired) => {\n            return secured_text(StatusCode::UNAUTHORIZED, \"bootstrap unavailable\");\n        }\n    };\n\n    let cookie = web_session_cookie(&session_token);\n    let mut response = (StatusCode::SEE_OTHER, \"\").into_response();\n    response\n        .headers_mut()\n        .insert(header::LOCATION, HeaderValue::from_static(\"/\"));\n    response.headers_mut().insert(\n        header::SET_COOKIE,\n        HeaderValue::from_str(&cookie).expect(\"percent-encoded Runtime cookie is a valid header\"),\n    );\n    secure_headers(&mut response, \"text/plain; charset=utf-8\");\n    response\n}\n\npub(super) async fn web_page(State(state): State<RuntimeApiState>) -> Response {\n    if state.web.is_none() {\n        return not_found();\n    }\n    secured_asset(\"text/html; charset=utf-8\", WEB_HTML)\n}\n\npub(super) async fn web_styles(State(state): State<RuntimeApiState>) -> Response {\n    if state.web.is_none() {\n        return not_found();\n    }\n    secured_asset(\"text/css; charset=utf-8\", WEB_CSS)\n}","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/runtime_api/web.rs#L116-L152","documentation":"Panic from `HeaderValue::from_str(&cookie)` while setting a Set-Cookie header in the runtime API bootstrap exchange. `from_str` fails only if the value contains non-visible-ASCII bytes; the code asserts the percent-encoded Runtime cookie is always header-safe.","triggerScenarios":"`exchange_bootstrap` producing a cookie containing raw non-ASCII, control characters, or newline bytes — i.e., the percent-encoding step failed to encode some character in the Runtime token.","commonSituations":"A token or session value containing characters outside the encoded alphabet after a change to cookie generation; non-UTF8-safe identifiers being embedded unencoded.","solutions":["Percent-encode the cookie value with `percent_encoding` covering all non-ASCII/control bytes before building the HeaderValue","Validate the cookie with `HeaderValue::from_str(...).is_ok()` and fail loudly at generation time","Log and reject tokens containing invalid characters at issuance instead of at header insertion"],"exampleFix":"// before\nresponse.headers_mut().insert(\n    header::SET_COOKIE,\n    HeaderValue::from_str(&cookie).expect(\"percent-encoded Runtime cookie is a valid header\"),\n);\n// after\nlet value = HeaderValue::from_str(&cookie)\n    .expect(\"percent-encoded Runtime cookie is a valid header; ensure token is fully percent-encoded\");\nresponse.headers_mut().insert(header::SET_COOKIE, value);","handlingStrategy":"validation","validationCode":"debug_assert!(HeaderValue::from_str(&cookie).is_ok(), \"cookie contains non-header-safe bytes: {:?}\", cookie);","typeGuard":"fn is_header_safe(v: &str) -> bool { HeaderValue::from_str(v).is_ok() }","tryCatchPattern":"let value = HeaderValue::from_str(&cookie).map_err(|e| anyhow::anyhow!(\"cookie not header-safe: {e}\"))?;","preventionTips":["Percent-encode every cookie component with a strict ASCII encode set","Round-trip test cookie generation with HeaderValue::from_str in CI","Reject tokens containing control or non-ASCII characters at issuance"],"tags":["rust","http","headers","cookie","encoding"],"backgroundTag":"invalid-argument-format","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}