{"record":{"id":"a32da17d056552a4","repo":"aaif-goose/goose","slug":"invalid-allowed-origin-value-origin-error","errorCode":null,"errorMessage":"invalid --allowed-origin value `{origin}`: {error}","messagePattern":"invalid --allowed-origin value `(.+?)`: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/goose-cli/src/cli.rs","lineNumber":1469,"sourceCode":"    if !require_token && !dangerously_unauthenticated {\n        anyhow::bail!(\n            \"{GOOSE_SERVER_SECRET_KEY_ENV} must be set to start `goose serve`; pass --dangerously-unauthenticated to run without ACP authentication\"\n        );\n    }\n    if dangerously_unauthenticated && !require_token {\n        warn!(\n            \"{GOOSE_SERVER_SECRET_KEY_ENV} is not set and --dangerously-unauthenticated was passed; the ACP endpoint will accept unauthenticated connections\"\n        );\n    }\n    let additional_allowed_origins = allowed_origins\n        .into_iter()\n        .map(|origin| {\n            let origin = origin.trim();\n            if origin.is_empty() || origin == \"*\" {\n                anyhow::bail!(\"--allowed-origin must be a non-wildcard Origin value\");\n            }\n            HeaderValue::from_str(origin).map_err(|error| {\n                anyhow::anyhow!(\"invalid --allowed-origin value `{origin}`: {error}\")\n            })\n        })\n        .collect::<Result<Vec<_>>>()?;\n    let secret_key = env_secret.unwrap_or_else(generate_serve_secret_key);\n    if let Err(error) = server.start_scheduler().await {\n        warn!(\"Scheduler failed to start; scheduled jobs will not run until a client connects: {error}\");\n    }\n    let router = create_router(\n        server,\n        secret_key,\n        require_token,\n        additional_allowed_origins,\n    );\n\n    let config = Config::global();\n    let tls_cert_path =\n        tls_cert_path.or_else(|| config.get_param::<String>(\"GOOSE_TLS_CERT_PATH\").ok());\n    let tls_key_path =","sourceCodeStart":1451,"sourceCodeEnd":1487,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-cli/src/cli.rs#L1451-L1487","documentation":"anyhow error from 'goose serve' origin validation (crates/goose-cli/src/cli.rs). After the wildcard/empty check, each --allowed-origin value is parsed with HeaderValue::from_str; values containing characters illegal in an HTTP header (spaces, control bytes, non-ASCII such as a URL with a path or unicode, or trailing newline/space that survived trimming of ends) produce this wrapping error with the underlying http crate message.","triggerScenarios":"Passing --allowed-origin values like 'http://localhost:3000/path' (origin must be scheme://host[:port] only), values with internal spaces, embedded newline/tab (unquoted shell escapes), unicode characters, or a value that is not a valid header string after the initial trim.","commonSituations":"Including a path or trailing slash in the origin; shell quoting bugs injecting whitespace/newlines; copying origins from a config that used wildcards like 'https://*.example.com' (invalid as a header value for this check and semantically unsupported); non-ASCII domain rendered as punycode-unconverted unicode.","solutions":["Use the strict origin form scheme://host[:port] with no path, query, or trailing slash: https://app.example.com","Fix shell quoting so no stray spaces/newlines reach the flag","For subdomain matching do not use '*' inside the value — list each concrete subdomain origin","If the host is non-ASCII, convert to punycode (xn--) form"],"exampleFix":"# before\ngoose serve --allowed-origin \"https://app.example.com/\"\ngoose serve --allowed-origin \"https://*.example.com\"\n\n# after\ngoose serve --allowed-origin https://app.example.com\ngoose serve --allowed-origin https://api.example.com","handlingStrategy":"validation","validationCode":"import re\nm = re.fullmatch(r\"(https?)://([^/:\\s]+)(:\\d{1,5})?\", origin.strip())\nif not m:\n    raise SystemExit(f\"not a valid origin (scheme://host[:port] only): {origin!r}\")","typeGuard":"def is_valid_origin_header(v: str) -> bool:\n    v = v.strip()\n    if not v or v == \"*\":\n        return False\n    try:\n        v.encode(\"ascii\")\n    except UnicodeEncodeError:\n        return False\n    return bool(re.fullmatch(r\"(https?)://[^/:\\s]+(:\\d{1,5})?\", v))","tryCatchPattern":null,"preventionTips":["Origin = scheme + host + optional port only: no path, no trailing slash","Quote flags properly; beware newlines from command substitution","Convert non-ASCII hosts to punycode","No wildcards inside the value (https://*.example.com is unsupported)"],"tags":["goose","serve","cors","http-header","validation"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}