{"record":{"id":"c5ebff4673f3dada","repo":"JuliusBrussee/caveman","slug":"vertex-publisher-q-is-not-on-the-allowlist","errorCode":null,"errorMessage":"vertex publisher %q is not on the allowlist","messagePattern":"vertex publisher %q is not on the allowlist","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/providers/vertex/routing.go","lineNumber":41,"sourceCode":"// Operators override it with CAVE_VERTEX_MODEL_ALLOWLIST.\nvar defaultModelPrefixes = []string{\"gemini-\", \"claude-\"}\n\n// ResolveUpstreamURL validates the Vertex request shape (publisher + model on\n// the allowlist), enforces SSRF/host constraints against the aiplatform\n// endpoint, and resolves the upstream URL. The /vertex prefix is stripped so the\n// upstream path is the native aiplatform path\n// (/v1/projects/{p}/locations/{l}/publishers/{pub}/models/{model}:{method}). The\n// query string (e.g. ?alt=sse) is preserved unchanged — byte-safe passthrough.\nfunc (a Adapter) ResolveUpstreamURL(ctx context.Context, req *http.Request, route providers.RouteContext) (*url.URL, error) {\n\tpublisher, model, method := parsePredictPath(req.URL.Path)\n\tif publisher == \"\" || model == \"\" || method == \"\" {\n\t\treturn nil, fmt.Errorf(\"vertex request path %q does not name a publisher, model, and method\", req.URL.Path)\n\t}\n\tif !methodAllowed(publisher, method) {\n\t\treturn nil, fmt.Errorf(\"vertex method %q is not allowed for publisher %q\", method, publisher)\n\t}\n\tif !publisherAllowed(publisher) {\n\t\treturn nil, fmt.Errorf(\"vertex publisher %q is not on the allowlist\", publisher)\n\t}\n\tif !modelAllowed(model) {\n\t\treturn nil, fmt.Errorf(\"vertex model %q is not on the allowlist\", model)\n\t}\n\n\tbaseURL := a.BaseURL\n\tif route.BaseURL != \"\" {\n\t\tbaseURL = route.BaseURL\n\t}\n\tbase, err := url.Parse(baseURL)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"vertex base url invalid: %w\", err)\n\t}\n\tbase.Path = strings.TrimRight(base.Path, \"/\") + strings.TrimPrefix(req.URL.Path, \"/vertex\")\n\tbase.RawQuery = req.URL.RawQuery\n\n\t// SSRF/host validation on the resolved endpoint. Active in managed (prod)\n\t// mode; local/self-hosted (stub) endpoints are permitted so the dry-run and","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/proxy/providers/vertex/routing.go#L23-L59","documentation":"The publisher segment of the Vertex path is not in defaultPublishers (\"google\", \"anthropic\"), so publisherAllowed rejected it. This is a deliberate cost-containment gate: requests to partner publishers the gateway does not price are refused before any upstream call.","triggerScenarios":"Thrown at proxy/providers/vertex/routing.go:41 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Use publisher google or anthropic in the path","Extend the publisher set (defaultPublishers) only after the model catalog covers the partner's pricing"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"766dce6b1394ebb56a3090748d5a0240a5aefb36","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}