aaif-goose/goose · error · anyhow::Error

invalid --allowed-origin value `{origin}`: {error}

Error message

invalid --allowed-origin value `{origin}`: {error}

What it means

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.

Source

Thrown at crates/goose-cli/src/cli.rs:1469

    if !require_token && !dangerously_unauthenticated {
        anyhow::bail!(
            "{GOOSE_SERVER_SECRET_KEY_ENV} must be set to start `goose serve`; pass --dangerously-unauthenticated to run without ACP authentication"
        );
    }
    if dangerously_unauthenticated && !require_token {
        warn!(
            "{GOOSE_SERVER_SECRET_KEY_ENV} is not set and --dangerously-unauthenticated was passed; the ACP endpoint will accept unauthenticated connections"
        );
    }
    let additional_allowed_origins = allowed_origins
        .into_iter()
        .map(|origin| {
            let origin = origin.trim();
            if origin.is_empty() || origin == "*" {
                anyhow::bail!("--allowed-origin must be a non-wildcard Origin value");
            }
            HeaderValue::from_str(origin).map_err(|error| {
                anyhow::anyhow!("invalid --allowed-origin value `{origin}`: {error}")
            })
        })
        .collect::<Result<Vec<_>>>()?;
    let secret_key = env_secret.unwrap_or_else(generate_serve_secret_key);
    if let Err(error) = server.start_scheduler().await {
        warn!("Scheduler failed to start; scheduled jobs will not run until a client connects: {error}");
    }
    let router = create_router(
        server,
        secret_key,
        require_token,
        additional_allowed_origins,
    );

    let config = Config::global();
    let tls_cert_path =
        tls_cert_path.or_else(|| config.get_param::<String>("GOOSE_TLS_CERT_PATH").ok());
    let tls_key_path =

View on GitHub (pinned to 3810898a74)

Solutions

  1. Use the strict origin form scheme://host[:port] with no path, query, or trailing slash: https://app.example.com
  2. Fix shell quoting so no stray spaces/newlines reach the flag
  3. For subdomain matching do not use '*' inside the value — list each concrete subdomain origin
  4. If the host is non-ASCII, convert to punycode (xn--) form

Example fix

# before
goose serve --allowed-origin "https://app.example.com/"
goose serve --allowed-origin "https://*.example.com"

# after
goose serve --allowed-origin https://app.example.com
goose serve --allowed-origin https://api.example.com
Defensive patterns

Strategy: validation

Validate before calling

import re
m = re.fullmatch(r"(https?)://([^/:\s]+)(:\d{1,5})?", origin.strip())
if not m:
    raise SystemExit(f"not a valid origin (scheme://host[:port] only): {origin!r}")

Type guard

def is_valid_origin_header(v: str) -> bool:
    v = v.strip()
    if not v or v == "*":
        return False
    try:
        v.encode("ascii")
    except UnicodeEncodeError:
        return False
    return bool(re.fullmatch(r"(https?)://[^/:\s]+(:\d{1,5})?", v))

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/a32da17d056552a4. Report an issue: GitHub.