{"record":{"id":"2eaf47dc4b04c2cb","repo":"Hmbown/CodeWhale","slug":"codewhale-account-api-base-url-must-be-an-origin-w","errorCode":null,"errorMessage":"Codewhale account API base URL must be an origin without a path","messagePattern":"Codewhale account API base URL must be an origin without a path","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/cli/src/cloud.rs","lineNumber":1024,"sourceCode":"    writeln!(out, \"API: {api_base}\")?;\n    Ok(())\n}\n\nstruct ValidatedApiBase {\n    url: Url,\n    display: String,\n}\n\nfn validate_api_base(value: &str) -> Result<ValidatedApiBase> {\n    let mut url = Url::parse(value.trim()).context(\"invalid Codewhale account API base URL\")?;\n    if !url.username().is_empty() || url.password().is_some() {\n        bail!(\"Codewhale account API base URL must not contain credentials\");\n    }\n    if url.query().is_some() || url.fragment().is_some() {\n        bail!(\"Codewhale account API base URL must not contain a query or fragment\");\n    }\n    if !matches!(url.path(), \"\" | \"/\") {\n        bail!(\"Codewhale account API base URL must be an origin without a path\");\n    }\n    let host = url\n        .host_str()\n        .ok_or_else(|| anyhow!(\"Codewhale account API base URL must include a host\"))?;\n    let allowed = url.scheme() == \"https\" || (url.scheme() == \"http\" && is_loopback_host(host));\n    if !allowed {\n        bail!(\n            \"Codewhale account API base URL must use HTTPS (loopback HTTP is allowed for testing)\"\n        );\n    }\n    url.set_path(\"/\");\n    let display = url.as_str().trim_end_matches('/').to_string();\n    Ok(ValidatedApiBase { url, display })\n}\n\nfn validate_verification_url(\n    value: &str,\n    api_base: &str,","sourceCodeStart":1006,"sourceCodeEnd":1042,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/cli/src/cloud.rs#L1006-L1042","documentation":"The API base URL must be an origin with no path component: validate_api_base allows only an empty path or /. The client constructs its own /api/... request paths, so a pre-set path would produce wrong URLs.","triggerScenarios":"Setting the base URL to something like https://api.example.com/v1 or https://example.com/api/codewhale.","commonSituations":"Reusing a base URL from another SDK that expects a path prefix (e.g. OpenAI-style /v1); pasting a full endpoint URL instead of the origin.","solutions":["Remove the path, keeping only scheme+host (and optional port): https://api.example.com.","Do not add /v1 or /api — the client appends its API paths itself.","Retry with the origin-only value."],"exampleFix":"// before\nCODEWHALE_API_BASE=https://api.example.com/v1\n// after\nCODEWHALE_API_BASE=https://api.example.com","handlingStrategy":"validation","validationCode":"fn has_no_path(url: &str) -> bool {\n    url::Url::parse(url.trim())\n        .map(|u| matches!(u.path(), \"\" | \"/\"))\n        .unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set base URLs without /v1 or /api prefixes — the client appends paths itself.","Use the origin (scheme + host + optional port) only.","Do not paste a full endpoint URL as the base.","Document the expected base form in deployment config templates."],"tags":["cli","url","validation"],"backgroundTag":"invalid-url-format","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}