{"record":{"id":"6d56f40b3ba12153","repo":"JuliusBrussee/caveman","slug":"vertex-model-q-is-not-on-the-allowlist","errorCode":null,"errorMessage":"vertex model %q is not on the allowlist","messagePattern":"vertex model %q is not on the allowlist","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/providers/vertex/routing.go","lineNumber":44,"sourceCode":"// 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\n\t// examples can target the provider-stub.\n\tif env.IsProduction() {\n\t\tif err := ssrf.ValidateURL(ctx, base.String(), ssrf.ManagedConfig()); err != nil {","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/proxy/providers/vertex/routing.go#L26-L62","documentation":"The model id from the path failed the prefix allowlist check (modelAllowed): it matches neither the built-in prefixes (gemini-, claude-) nor any operator override from CAVE_VERTEX_MODEL_ALLOWLIST. The gate blocks unpriced or unauthorized model ids before the upstream URL is built.","triggerScenarios":"Thrown at proxy/providers/vertex/routing.go:44 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Use an allowed model id such as gemini-2.5-pro or claude-sonnet-4-5","Set CAVE_VERTEX_MODEL_ALLOWLIST to add the desired model prefix if the catalog prices it"],"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"}