{"record":{"id":"8abdfcc6faa1e23b","repo":"astrid-runtime/astrid","slug":"cors-origin-raw-must-be-ascii-only-punycode","errorCode":null,"errorMessage":"CORS origin {raw:?} must be ASCII-only (Punycode); browsers send the Punycoded form in `Origin:`. Use {parsed_ascii:?} instead.","messagePattern":"CORS origin (.+?) must be ASCII-only \\(Punycode\\); browsers send the Punycoded form in `Origin:`\\. Use (.+?) instead\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-gateway/src/config.rs","lineNumber":232,"sourceCode":"        anyhow::bail!(\n            \"CORS origin {raw:?} carries a query/fragment; origins are scheme+host+port only\"\n        );\n    }\n    // Disallow trailing-slash forms — browsers send `https://app.example`\n    // (no slash) in `Origin:` and the response header is byte-matched.\n    if raw.ends_with('/') {\n        anyhow::bail!(\n            \"CORS origin {raw:?} has a trailing slash; remove it (browsers send `Origin:` without one)\"\n        );\n    }\n    // Reject a raw IDN — browsers transmit the Punycode (ASCII)\n    // form in `Origin:`, so the bytes wouldn't match anyway. The\n    // `Url` parser already normalizes the host to its ASCII form on\n    // parse; if the *raw* string contained a non-ASCII character,\n    // the parsed `origin()` ASCII-serialization won't equal `raw`.\n    let parsed_ascii = parsed.origin().ascii_serialization();\n    if parsed_ascii != raw {\n        anyhow::bail!(\n            \"CORS origin {raw:?} must be ASCII-only (Punycode); browsers send the Punycoded form in `Origin:`. Use {parsed_ascii:?} instead.\"\n        );\n    }\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn default_is_disabled() {\n        let cfg = GatewayConfig::default();\n        assert!(!cfg.enabled);\n        assert_eq!(cfg.listen, \"127.0.0.1:2787\");\n    }\n\n    fn cfg_with_cors(origins: Vec<&str>) -> GatewayConfig {","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-gateway/src/config.rs#L214-L250","documentation":"Validation guard in validate_cors_origin: the entry is a raw IDN (non-ASCII hostname), but browsers transmit the Punycoded ASCII form in Origin:, so the raw bytes would never match; the error names the precomputed ASCII form to use instead.","triggerScenarios":"Thrown at crates/astrid-gateway/src/config.rs:232 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Replace the IDN with the Punycoded ASCII origin given in the error message (e.g. https://xn--...:)","Convert the hostname with an IDNA/punycode tool and re-enter it","Verify the converted origin against a real browser preflight"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}