BerriAI/litellm · error · ValueError

Custom code guardrail requires 'custom_code' in litellm_para

Error message

Custom code guardrail requires 'custom_code' in litellm_params

What it means

ValueError raised by the custom-code guardrail factory when the guardrails entry routes to the custom-code guardrail (guardrail_name is present) but litellm_params has no custom_code attribute or it is empty. The guardrail is entirely defined by that code string, so its absence is a config schema violation caught at instantiation.

Source

Thrown at litellm/proxy/guardrails/guardrail_hooks/custom_code/__init__.py:44

    Initialize a custom code guardrail.

    Args:
        litellm_params: Configuration parameters including the custom code
        guardrail: The guardrail configuration dict

    Returns:
        CustomCodeGuardrail instance
    """
    import litellm

    guardrail_name: Final = guardrail.get("guardrail_name")
    if not guardrail_name:
        raise ValueError("Custom code guardrail requires a guardrail_name")

    # Get the custom code from litellm_params
    custom_code: Final = getattr(litellm_params, "custom_code", None)
    if not custom_code:
        raise ValueError("Custom code guardrail requires 'custom_code' in litellm_params")

    custom_code_guardrail: Final = CustomCodeGuardrail(
        guardrail_name=guardrail_name,
        custom_code=custom_code,
        event_hook=litellm_params.mode,
        default_on=litellm_params.default_on,
    )

    litellm.logging_callback_manager.add_litellm_callback(custom_code_guardrail)
    return custom_code_guardrail


guardrail_initializer_registry: Final = {
    SupportedGuardrailIntegrations.CUSTOM_CODE.value: initialize_guardrail,
}

guardrail_class_registry: Final = {
    SupportedGuardrailIntegrations.CUSTOM_CODE.value: CustomCodeGuardrail,

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Add custom_code under litellm_params with a block scalar containing def apply_guardrail(...)
  2. Check the block-scalar indentation (code lines must be indented consistently under custom_code: |)
  3. Render and inspect the final YAML (e.g. yaml.safe_load) in CI to confirm the key is a non-empty string

Example fix

# before
guardrails:
  - guardrail_name: my-custom-guardrail
    litellm_params:
      mode: guardrail_runs_before_llm_call

# after
guardrails:
  - guardrail_name: my-custom-guardrail
    litellm_params:
      mode: guardrail_runs_before_llm_call
      custom_code: |
        def apply_guardrail(inputs, request_data, input_type):
            for text in inputs.get('texts') or []:
                if 'forbidden' in text:
                    return block('forbidden term')
            return allow()
Defensive patterns

Strategy: validation

Validate before calling

import yaml

cfg = yaml.safe_load(open('config.yaml'))
for g in cfg.get('guardrails') or []:
    lp = g.get('litellm_params') or {}
    if not isinstance(lp.get('custom_code'), str) or not lp['custom_code'].strip():
        raise ValueError(f"guardrail {g.get('guardrail_name')}: litellm_params.custom_code must be a non-empty string")

Try / catch

try:
    guardrail = instantiate_custom_code_guardrail(litellm_params=lp, guardrail=entry)
except ValueError as e:
    # config rejected before any traffic is served
    raise SystemExit(f'invalid guardrail config: {e}') from e

Prevention

When it happens

Trigger: A guardrails entry with guardrail_name and a custom-code mode in litellm_params but no custom_code key; or custom_code set to an empty string/None (e.g. templated config rendered the value empty).

Common situations: Mode set from an example but the code block not filled in; YAML block scalar (custom_code: |) with wrong indentation so the value parses as empty; CI templating stripping the field.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/e5ad3431e3965b6f. Report an issue: GitHub.