{"record":{"id":"5a7ee38f38baf6c8","repo":"BerriAI/litellm","slug":"invalid-guardrailconfig-raw-guardrail-config-ex","errorCode":null,"errorMessage":"Invalid guardrailConfig={raw_guardrail_config}. Expected format: {_GUARDRAIL_CONFIG_EXPECTED_FORMAT}. Error: {e}","messagePattern":"Invalid guardrailConfig=(.+?)\\. Expected format: (.+?)\\. Error: (.+?)","errorType":"http","errorClass":"BedrockError","httpStatus":400,"severity":"error","filePath":"litellm/llms/bedrock/chat/invoke_transformations/base_invoke_transformation.py","lineNumber":53,"sourceCode":"\n    LiteLLMLoggingObj = _LiteLLMLoggingObj\nelse:\n    LiteLLMLoggingObj = Any\n\nfrom litellm.llms.bedrock.base_aws_llm import BaseAWSLLM\n\n_GUARDRAIL_CONFIG_VALIDATOR: Final[\"TypeAdapter[GuardrailConfigBlock]\"] = TypeAdapter(GuardrailConfigBlock)\n\n_GUARDRAIL_CONFIG_EXPECTED_FORMAT: Final = (\n    \"{'guardrailIdentifier': str, 'guardrailVersion': str, 'trace': 'enabled'|'disabled'|'enabled_full'}\"\n)\n\n\ndef _bedrock_invoke_guardrail_headers(raw_guardrail_config: object) -> \"dict[str, str]\":\n    try:\n        guardrail_config: Final = _GUARDRAIL_CONFIG_VALIDATOR.validate_python(raw_guardrail_config)\n    except ValidationError as e:\n        raise BedrockError(\n            status_code=400,\n            message=f\"Invalid guardrailConfig={raw_guardrail_config}. Expected format: {_GUARDRAIL_CONFIG_EXPECTED_FORMAT}. Error: {e}\",\n        )\n    if \"guardrailIdentifier\" not in guardrail_config:\n        raise BedrockError(\n            status_code=400,\n            message=f\"guardrailConfig={raw_guardrail_config} is missing 'guardrailIdentifier'. Expected format: {_GUARDRAIL_CONFIG_EXPECTED_FORMAT}\",\n        )\n    trace: Final = guardrail_config.get(\"trace\")\n    candidate_headers: Final = {\n        \"X-Amzn-Bedrock-GuardrailIdentifier\": guardrail_config.get(\"guardrailIdentifier\"),\n        \"X-Amzn-Bedrock-GuardrailVersion\": guardrail_config.get(\"guardrailVersion\"),\n        \"X-Amzn-Bedrock-Trace\": trace.upper() if trace is not None else None,\n    }\n    return {name: value for name, value in candidate_headers.items() if value is not None}\n\n\nclass AmazonInvokeConfig(BaseConfig, BaseAWSLLM):","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/bedrock/chat/invoke_transformations/base_invoke_transformation.py#L35-L71","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nresp = litellm.completion(\n    model=\"bedrock/anthropic.claude-3-sonnet-20240229-v1:0\",\n    messages=msgs,\n    extra_body={\"guardrailConfig\": '{\"guardrailIdentifier\": \"gr-123\"}'},  # JSON string - invalid\n)\n\n# after\nimport json\nresp = litellm.completion(\n    model=\"bedrock/anthropic.claude-3-sonnet-20240229-v1:0\",\n    messages=msgs,\n    extra_body={\"guardrailConfig\": {\n        \"guardrailIdentifier\": \"gr-123\",\n        \"guardrailVersion\": \"1\",\n        \"trace\": \"enabled\",\n    }},\n)","handlingStrategy":"validation","validationCode":"ALLOWED_TRACE = {\"enabled\", \"disabled\", \"enabled_full\"}\ndef validate_guardrail_config(cfg):\n    if not isinstance(cfg, dict):\n        raise ValueError(\"guardrailConfig must be a dict\")\n    if \"guardrailIdentifier\" not in cfg or not isinstance(cfg[\"guardrailIdentifier\"], str):\n        raise ValueError(\"guardrailIdentifier must be a str\")\n    if not isinstance(cfg.get(\"guardrailVersion\", \"\"), str):\n        raise ValueError(\"guardrailVersion must be a str (quote it: '1')\")\n    if cfg.get(\"trace\") is not None and cfg[\"trace\"] not in ALLOWED_TRACE:\n        raise ValueError(f\"trace must be one of {ALLOWED_TRACE}\")\n    return cfg","typeGuard":"def is_valid_guardrail_config(cfg: object) -> bool:\n    return (\n        isinstance(cfg, dict)\n        and isinstance(cfg.get(\"guardrailIdentifier\"), str)\n        and isinstance(cfg.get(\"guardrailVersion\", \"\"), str)\n        and cfg.get(\"trace\", \"enabled\") in {\"enabled\", \"disabled\", \"enabled_full\"}\n    )","tryCatchPattern":"from litellm.exceptions import BedrockError\ntry:\n    resp = litellm.completion(model=\"bedrock/<model>\", messages=msgs, extra_body={\"guardrailConfig\": cfg})\nexcept BedrockError as e:\n    if e.status_code == 400 and \"Invalid guardrailConfig\" in str(e):\n        raise ValueError(f\"bad guardrail config from user input: {e.message}\") from e\n    raise","preventionTips":["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."],"tags":["aws","bedrock","guardrails","validation","configuration"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}