JuliusBrussee/caveman · error

bedrock action is not allowed

Error message

bedrock action %q is not allowed

What it means

Only a fixed set of Runtime actions is allowed on /bedrock/model/{modelId}/{action}: invoke, invoke-with-response-stream, converse, converse-stream, and count-tokens. Any other trailing action segment is rejected so clients cannot invoke arbitrary Bedrock APIs through the proxy.

Solutions

  1. Use one of the allowed actions: invoke, invoke-with-response-stream, converse, converse-stream, or count-tokens.
  2. For embeddings or other Bedrock APIs, call them directly against AWS rather than through this proxy route.
  3. Check casing — actions are matched exactly, lowercase.

Example fix

// before
POST /bedrock/model/anthropic.claude-3-5-sonnet/invoke-agent
// after
POST /bedrock/model/anthropic.claude-3-5-sonnet/converse
Defensive patterns

Strategy: validation

Validate before calling

var allowedActions = map[string]bool{
	"invoke": true, "invoke-with-response-stream": true,
	"converse": true, "converse-stream": true, "count-tokens": true,
}
func actionAllowed(path string) bool {
	seg := path[strings.LastIndex(path, "/")+1:]
	return allowedActions[seg]
}

Prevention

When it happens

Trigger: A /bedrock/model/{modelId}/{action} request where action is something other than the five allowed values — e.g. /invoke-agent, /converse-stream-v2, /embeddings, or a mixed-case variant like /Invoke.

Common situations: Trying to reach other Bedrock APIs (agents, guardrails, embeddings/titan-embed) through the model route; SDK emitting a newer action name the proxy has not allowlisted; case-sensitivity mistakes.

Related errors


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

Appendix: source

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

	if err != nil {
		return nil, err
	}

	kind := endpointKindForPath(req.URL.Path)
	if configuredKind := strings.ToLower(strings.TrimSpace(route.EndpointKind)); configuredKind != "" && configuredKind != kind {
		return nil, fmt.Errorf("bedrock configured endpoint kind %q does not allow request kind %q", configuredKind, kind)
	}
	switch kind {
	case endpointRuntime:
		if !RegionAllowed(region) {
			return nil, fmt.Errorf("bedrock region %q is not on the allowlist", region)
		}
		modelID, action := parseModelPath(req.URL.Path)
		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

View on GitHub (pinned to 3ee70a1026)