JuliusBrussee/caveman · error

vertex method %q is not allowed for publisher %q

Error message

vertex method %q is not allowed for publisher %q

What it means

ResolveUpstreamURL parsed the publisher and method from the path, but methodAllowed(publisher, method) rejected the combination: each publisher (google, anthropic) only permits its own method set (e.g. anthropic models only accept anthropic-native methods, not gemini generateContent). It fires on cross-family method misuse before allowlist or SSRF checks run.

Source

Thrown at proxy/providers/vertex/routing.go:38

// defaultModelPrefixes is the built-in model-id allowlist, matched as prefixes
// so versioned ids (gemini-2.5-pro, claude-sonnet-4-5@20250929) are covered.
// Operators override it with CAVE_VERTEX_MODEL_ALLOWLIST.
var defaultModelPrefixes = []string{"gemini-", "claude-"}

// ResolveUpstreamURL validates the Vertex request shape (publisher + model on
// the allowlist), enforces SSRF/host constraints against the aiplatform
// endpoint, and resolves the upstream URL. The /vertex prefix is stripped so the
// upstream path is the native aiplatform path
// (/v1/projects/{p}/locations/{l}/publishers/{pub}/models/{model}:{method}). The
// query string (e.g. ?alt=sse) is preserved unchanged — byte-safe passthrough.
func (a Adapter) ResolveUpstreamURL(ctx context.Context, req *http.Request, route providers.RouteContext) (*url.URL, error) {
	publisher, model, method := parsePredictPath(req.URL.Path)
	if publisher == "" || model == "" || method == "" {
		return nil, fmt.Errorf("vertex request path %q does not name a publisher, model, and method", req.URL.Path)
	}
	if !methodAllowed(publisher, method) {
		return nil, fmt.Errorf("vertex method %q is not allowed for publisher %q", method, publisher)
	}
	if !publisherAllowed(publisher) {
		return nil, fmt.Errorf("vertex publisher %q is not on the allowlist", publisher)
	}
	if !modelAllowed(model) {
		return nil, fmt.Errorf("vertex model %q is not on the allowlist", model)
	}

	baseURL := a.BaseURL
	if route.BaseURL != "" {
		baseURL = route.BaseURL
	}
	base, err := url.Parse(baseURL)
	if err != nil {
		return nil, fmt.Errorf("vertex base url invalid: %w", err)
	}
	base.Path = strings.TrimRight(base.Path, "/") + strings.TrimPrefix(req.URL.Path, "/vertex")
	base.RawQuery = req.URL.RawQuery

View on GitHub (pinned to 766dce6b13)

Solutions

  1. Use a method supported by the named publisher, e.g. generateContent/streamGenerateContent for google and the anthropic method for anthropic
  2. Verify the client is not sending a Gemini-style path to a claude publisher or vice versa
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at proxy/providers/vertex/routing.go:38 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18). Data as JSON: /api/errors/b891b3610198d5f5. Report an issue: GitHub.