{"record":{"id":"552ac233cc64278e","repo":"aaif-goose/goose","slug":"allowed-origin-must-be-a-non-wildcard-origin-val","errorCode":null,"errorMessage":"--allowed-origin must be a non-wildcard Origin value","messagePattern":"--allowed-origin must be a non-wildcard Origin value","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/goose-cli/src/cli.rs","lineNumber":1466,"sourceCode":"        .map(|secret| secret.trim().to_string())\n        .filter(|secret| !secret.is_empty());\n    let require_token = env_secret.is_some();\n    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();","sourceCodeStart":1448,"sourceCodeEnd":1484,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-cli/src/cli.rs#L1448-L1484","documentation":"anyhow bail from 'goose serve' origin validation (crates/goose-cli/src/cli.rs). Each --allowed-origin value is trimmed and rejected if it is empty or exactly '*': CORS origins must be concrete values, and wildcard CORS is not offered via this flag (auth via secret key remains mandatory instead).","triggerScenarios":"Running 'goose serve --allowed-origin \"*\"' or passing an empty/whitespace-only value (e.g. an env expansion that produced an empty string): origin.is_empty() || origin == \"*\" triggers the bail before HeaderValue parsing.","commonSituations":"Copy-pasting a permissive CORS setup from another tool; shell loops building --allowed-origin flags from a variable that is sometimes empty; misunderstanding that goose gates cross-origin access via the token, not via CORS wildcard.","solutions":["Pass concrete origins: --allowed-origin http://localhost:1420 --allowed-origin https://app.example.com","If a script builds flags from variables, skip the flag when the variable is empty","Do not rely on '*' — connect clients are authenticated with the GOOSE_SERVER__SECRET_KEY token instead","List each origin you actually serve from (dev server port + production domain)"],"exampleFix":"# before\ngoose serve --allowed-origin '*'\n\n# after\ngoose serve --allowed-origin http://localhost:1420 --allowed-origin https://app.example.com","handlingStrategy":"validation","validationCode":"origin = origin.strip()\nif not origin or origin == \"*\":\n    raise SystemExit(\"--allowed-origin must be a concrete origin like https://app.example.com\")","typeGuard":"def is_concrete_origin(v: str) -> bool:\n    v = v.strip()\n    return bool(v) and v != \"*\" and not v.endswith('/')","tryCatchPattern":null,"preventionTips":["Never pass '*' — goose authorizes clients by token, not CORS wildcard","List each concrete origin explicitly","Skip empty flags when building the command from variables in scripts"],"tags":["goose","serve","cors","argument-validation"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}