BerriAI/litellm · error · BedrockError
Invalid guardrailConfig={raw_guardrail_config}. Expected for
Error message
Invalid guardrailConfig={raw_guardrail_config}. Expected format: {_GUARDRAIL_CONFIG_EXPECTED_FORMAT}. Error: {e} What it means
Raised by _bedrock_invoke_guardrail_headers when the guardrailConfig parameter fails pydantic TypeAdapter validation against GuardrailConfigBlock. The message embeds the offending value, the expected shape ({'guardrailIdentifier': str, 'guardrailVersion': str, 'trace': 'enabled'|'disabled'|'enabled_full'}) and the pydantic ValidationError detail. It is a BedrockError 400 (bad request configuration).
Source
Thrown at litellm/llms/bedrock/chat/invoke_transformations/base_invoke_transformation.py:53
LiteLLMLoggingObj = _LiteLLMLoggingObj
else:
LiteLLMLoggingObj = Any
from litellm.llms.bedrock.base_aws_llm import BaseAWSLLM
_GUARDRAIL_CONFIG_VALIDATOR: Final["TypeAdapter[GuardrailConfigBlock]"] = TypeAdapter(GuardrailConfigBlock)
_GUARDRAIL_CONFIG_EXPECTED_FORMAT: Final = (
"{'guardrailIdentifier': str, 'guardrailVersion': str, 'trace': 'enabled'|'disabled'|'enabled_full'}"
)
def _bedrock_invoke_guardrail_headers(raw_guardrail_config: object) -> "dict[str, str]":
try:
guardrail_config: Final = _GUARDRAIL_CONFIG_VALIDATOR.validate_python(raw_guardrail_config)
except ValidationError as e:
raise BedrockError(
status_code=400,
message=f"Invalid guardrailConfig={raw_guardrail_config}. Expected format: {_GUARDRAIL_CONFIG_EXPECTED_FORMAT}. Error: {e}",
)
if "guardrailIdentifier" not in guardrail_config:
raise BedrockError(
status_code=400,
message=f"guardrailConfig={raw_guardrail_config} is missing 'guardrailIdentifier'. Expected format: {_GUARDRAIL_CONFIG_EXPECTED_FORMAT}",
)
trace: Final = guardrail_config.get("trace")
candidate_headers: Final = {
"X-Amzn-Bedrock-GuardrailIdentifier": guardrail_config.get("guardrailIdentifier"),
"X-Amzn-Bedrock-GuardrailVersion": guardrail_config.get("guardrailVersion"),
"X-Amzn-Bedrock-Trace": trace.upper() if trace is not None else None,
}
return {name: value for name, value in candidate_headers.items() if value is not None}
class AmazonInvokeConfig(BaseConfig, BaseAWSLLM):View on GitHub (pinned to 6c2dcb801b)
Solutions
- Pass a plain dict with string values: {'guardrailIdentifier': '<id-or-arn>', 'guardrailVersion': '1', 'trace': 'enabled'}.
- Parse JSON strings first (json.loads) before handing them to litellm.
- Read the embedded pydantic error - it names exactly which key/type failed.
- Ensure guardrailVersion is quoted ('1', not 1) and trace is one of the three allowed strings.
Example fix
# before
resp = litellm.completion(
model="bedrock/anthropic.claude-3-sonnet-20240229-v1:0",
messages=msgs,
extra_body={"guardrailConfig": '{"guardrailIdentifier": "gr-123"}'}, # JSON string - invalid
)
# after
import json
resp = litellm.completion(
model="bedrock/anthropic.claude-3-sonnet-20240229-v1:0",
messages=msgs,
extra_body={"guardrailConfig": {
"guardrailIdentifier": "gr-123",
"guardrailVersion": "1",
"trace": "enabled",
}},
) Defensive patterns
Strategy: validation
Validate before calling
ALLOWED_TRACE = {"enabled", "disabled", "enabled_full"}
def validate_guardrail_config(cfg):
if not isinstance(cfg, dict):
raise ValueError("guardrailConfig must be a dict")
if "guardrailIdentifier" not in cfg or not isinstance(cfg["guardrailIdentifier"], str):
raise ValueError("guardrailIdentifier must be a str")
if not isinstance(cfg.get("guardrailVersion", ""), str):
raise ValueError("guardrailVersion must be a str (quote it: '1')")
if cfg.get("trace") is not None and cfg["trace"] not in ALLOWED_TRACE:
raise ValueError(f"trace must be one of {ALLOWED_TRACE}")
return cfg Type guard
def is_valid_guardrail_config(cfg: object) -> bool:
return (
isinstance(cfg, dict)
and isinstance(cfg.get("guardrailIdentifier"), str)
and isinstance(cfg.get("guardrailVersion", ""), str)
and cfg.get("trace", "enabled") in {"enabled", "disabled", "enabled_full"}
) Try / catch
from litellm.exceptions import BedrockError
try:
resp = litellm.completion(model="bedrock/<model>", messages=msgs, extra_body={"guardrailConfig": cfg})
except BedrockError as e:
if e.status_code == 400 and "Invalid guardrailConfig" in str(e):
raise ValueError(f"bad guardrail config from user input: {e.message}") from e
raise Prevention
- Validate guardrailConfig shape at the API boundary before it reaches litellm.
- Always json.loads config strings received from users/config files.
- Quote guardrailVersion and restrict trace to the three allowed enum strings.
When it happens
Trigger: Passing guardrail_config (or extra_body guardrailConfig) to a bedrock/ invoke call as a string, list, or dict with wrong types - e.g. guardrailVersion as an int, trace set to 'on', or the whole config passed as a JSON string instead of a dict.
Common situations: Copying AWS CLI JSON examples into the Python SDK without parsing them (left as a string), version drift where trace gained new enum values, or constructing the config from untyped user input.
Related errors
- guardrailConfig={raw_guardrail_config} is missing 'guardrail
- AWS region not set: set AWS_REGION_NAME or AWS_REGION env va
- S3 bucket name is required. Set 's3_bucket_name' parameter o
- Setting tag based guardrail modes is only available in litel
- Invalid mode: {custom_auth_settings['mode']}
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/5a7ee38f38baf6c8.
Report an issue: GitHub.