{"record":{"id":"8282055c41923c05","repo":"JuliusBrussee/caveman","slug":"compat-upstream-q-base-url-is-required","errorCode":null,"errorMessage":"compat upstream %q: base_url is required","messagePattern":"compat upstream %q: base_url is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/internal/config/config.go","lineNumber":458,"sourceCode":"}\n\n// BedrockBaseURL returns an explicit operator override or derives AWS's standard\n// Runtime endpoint from BedrockRegion. Callers never need to paste a raw URL for\n// the normal first-party path.\nfunc (c Config) BedrockBaseURL() string {\n\tif configured := c.BaseURL(\"bedrock\", \"\"); configured != \"\" {\n\t\treturn configured\n\t}\n\treturn fmt.Sprintf(\"https://bedrock-runtime.%s.amazonaws.com\", c.BedrockRegion())\n}\n\nfunc (c Config) validateCompat() error {\n\tfor name, upstream := range c.Compat {\n\t\tif err := openaicompat.ValidateName(name); err != nil {\n\t\t\treturn fmt.Errorf(\"compat upstream %q: %w\", name, err)\n\t\t}\n\t\tif strings.TrimSpace(upstream.BaseURL) == \"\" {\n\t\t\treturn fmt.Errorf(\"compat upstream %q: base_url is required\", name)\n\t\t}\n\t\tif err := openaicompat.ValidateBaseURL(upstream.BaseURL); err != nil {\n\t\t\treturn fmt.Errorf(\"compat upstream %q: base_url: %w\", name, err)\n\t\t}\n\t\tif err := openaicompat.ValidateForwardHeaders(upstream.ForwardHeaders); err != nil {\n\t\t\treturn fmt.Errorf(\"compat upstream %q: forward_headers: %w\", name, err)\n\t\t}\n\t\tif err := openaicompat.ValidateWireDialect(upstream.WireDialect); err != nil {\n\t\t\treturn fmt.Errorf(\"compat upstream %q: %w\", name, err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// providerEnvKey maps a provider name to the BYOK environment variable that\n// holds its API key.\nvar providerEnvKey = map[string]string{\n\t\"anthropic\":         \"ANTHROPIC_API_KEY\",","sourceCodeStart":440,"sourceCodeEnd":476,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/internal/config/config.go#L440-L476","documentation":"A compat upstream entry was defined but its base_url is empty or whitespace-only. The proxy cannot route OpenAI-compatible requests to an upstream without an endpoint URL, so validateCompat rejects it at load time.","triggerScenarios":"Defining a compat upstream section with only a name (e.g. [compat.\"foo\"] with no fields), or setting base_url = \"\" or base_url = \"   \" in the config file, then calling Load.","commonSituations":"Scaffolding a new upstream entry and forgetting to fill in base_url; a templating step that omitted empty values; hand-edited TOML/JSON/YAML with the key deleted.","solutions":["Set base_url to the upstream's full API endpoint, e.g. \"https://api.example.com/v1\".","Remove the empty compat upstream entry entirely if it is not used.","If base_url is injected from env/templating, fix the empty substitution in the pipeline."],"exampleFix":"// before\n[compat.\"foo\"]\n// after\n[compat.\"foo\"]\nbase_url = \"https://api.example.com/v1\"","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(upstream.BaseURL) == \"\" {\n    return fmt.Errorf(\"compat upstream %q: base_url is required\", name)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use a config schema/template where base_url is a required field for every compat entry.","Check templating pipelines don't drop empty values silently.","Validate configs at startup in staging before production."],"tags":["config","compat","missing-field"],"backgroundTag":"missing-required-config-field","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}