JuliusBrussee/caveman · error

bedrock Mantle path is not allowed

Error message

bedrock Mantle path %q is not allowed

What it means

The implemented Mantle lane serves exactly two paths: /bedrock/anthropic/v1/messages and /bedrock/anthropic/v1/messages/count_tokens. Any other path under /bedrock/anthropic/ (AWS's OpenAI-compatible Mantle surfaces are deliberately not routed yet) is rejected by mantleActionAllowed in ResolveUpstreamURL.

Solutions

  1. Use exactly POST /bedrock/anthropic/v1/messages (or .../v1/messages/count_tokens) — check for typos and trailing slashes
  2. If you need the OpenAI-compatible surface or legacy completions, route via a different provider adapter; Mantle here is Anthropic-Messages-only
  3. If targeting Bedrock Runtime model invocation, use /bedrock/model/<modelId>/invoke|converse instead
  4. Upgrade the proxy if a newer Mantle path was recently added to AWS and you need support for it

Example fix

// before
POST /bedrock/anthropic/v1/message  // typo -> rejected
// after
POST /bedrock/anthropic/v1/messages
Defensive patterns

Strategy: validation

Validate before calling

allowedMantle := map[string]bool{"/bedrock/anthropic/v1/messages": true, "/bedrock/anthropic/v1/messages/count_tokens": true}
if !allowedMantle[path] {
	// correct the path before sending
}

Prevention

When it happens

Trigger: A request like POST /bedrock/anthropic/v1/complete, /bedrock/anthropic/v1/chat/completions, /bedrock/anthropic/v1/models, or a mistyped messages path (e.g. /bedrock/anthropic/v1/message) while endpointKindForPath classifies it as Mantle (prefix /bedrock/anthropic/).

Common situations: Pointing an OpenAI SDK-style client at the Mantle prefix; using the legacy Anthropic /v1/complete endpoint; a trailing-slash or typo variant of /v1/messages; assuming all Anthropic API paths are proxied through Mantle.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/d5f21e974713aa18. Report an issue: GitHub.

Appendix: source

Thrown at proxy/providers/bedrock/routing.go:189

		if modelID == "" || action == "" {
			return nil, fmt.Errorf("bedrock request path %q does not name a model and action", req.URL.Path)
		}
		if !actionAllowed(action) {
			return nil, fmt.Errorf("bedrock action %q is not allowed", action)
		}
		if !modelAllowed(modelID) {
			return nil, fmt.Errorf("bedrock model %q is not on the allowlist", modelID)
		}
		base.Path = strings.TrimRight(base.Path, "/") + strings.TrimPrefix(req.URL.Path, "/bedrock")
	case endpointMantle:
		if !env.Bool("CAVE_BEDROCK_MANTLE_ENABLED", false) {
			return nil, fmt.Errorf("bedrock Mantle endpoint is not enabled")
		}
		if !MantleRegionAllowed(region) {
			return nil, fmt.Errorf("bedrock Mantle region %q is not on the allowlist", region)
		}
		if !mantleActionAllowed(req.URL.Path) {
			return nil, fmt.Errorf("bedrock Mantle path %q is not allowed", req.URL.Path)
		}
		base, err = resolveMantleBase(base, region)
		if err != nil {
			return nil, err
		}
		base.Path = strings.TrimRight(base.Path, "/") + strings.TrimPrefix(req.URL.Path, "/bedrock")
	default:
		return nil, fmt.Errorf("bedrock request path %q is not allowed", req.URL.Path)
	}
	base.RawQuery = req.URL.RawQuery

	if env.IsProduction() {
		if err := providers.ValidateUpstreamEndpoint(ctx, base, ssrf.ManagedConfig()); err != nil {
			return nil, err
		}
		hostKind, _, ok := bedrockHostKind(base.Hostname())
		if !ok || hostKind != kind {
			return nil, fmt.Errorf("bedrock endpoint host %q does not match endpoint kind %q", base.Hostname(), kind)

View on GitHub (pinned to 3ee70a1026)