BerriAI/litellm · error · CustomCodeExecutionError
Custom code guardrail execution failed: {e}
Error message
Custom code guardrail execution failed: {e} What it means
CustomCodeExecutionError raised when the user's apply_guardrail function itself raises any exception other than the guardrail's own control-flow exceptions (HTTPException from block actions, ModifyResponseException from passthrough). The original exception is chained and details include guardrail_name and input_type — the failure is in the custom code's runtime logic, not in compilation or the sandbox.
Source
Thrown at litellm/proxy/guardrails/guardrail_hooks/custom_code/custom_code_guardrail.py:258
result = await result
# Process the result
return self._process_result(
result=result,
inputs=inputs,
request_data=request_data,
input_type=input_type,
)
except HTTPException:
# Re-raise HTTP exceptions (from block action)
raise
except ModifyResponseException:
# Pre-call block uses passthrough; must not wrap as execution error (500)
raise
except Exception as e:
verbose_proxy_logger.error("Custom code guardrail '%s' execution error: %s", self.guardrail_name, e)
raise CustomCodeExecutionError(
f"Custom code guardrail execution failed: {e}",
details={
"guardrail_name": self.guardrail_name,
"input_type": input_type,
},
) from e
def _prepare_safe_request_data(self, request_data: dict) -> dict[str, Any]:
"""
Prepare a safe subset of request_data for code execution.
This filters out sensitive information and provides only what's
needed for guardrail logic.
Args:
request_data: The full request data
Returns:View on GitHub (pinned to 77b7c6c40c)
Solutions
- Read the wrapped message and __cause__ — they contain the original error from your function
- Access inputs defensively (inputs.get('texts') or []) and wrap sandbox HTTP calls in try/except inside the custom code
- Unit-test the exact custom_code string against representative inputs outside the proxy before deploying
- Decide fail-open vs fail-closed explicitly: return allow() on unexpected internal errors only if skipping the check is acceptable
Example fix
# before: crashes on shape assumptions and HTTP failures
async def apply_guardrail(inputs, request_data, input_type):
text = inputs['texts'][0]
r = await http_post('https://mod.example/check', body={'text': text})
if r['body']['flagged']:
return block('flagged')
return allow()
# after: guarded access, explicit failure policy
async def apply_guardrail(inputs, request_data, input_type):
for text in (inputs or {}).get('texts') or []:
try:
r = await http_post('https://mod.example/check', body={'text': text})
except Exception:
return allow() # fail-open; use block(...) if you need fail-closed
if (r.get('body') or {}).get('flagged'):
return block('flagged by moderation API')
return allow() Defensive patterns
Strategy: try-catch
Validate before calling
from litellm.proxy.guardrails.guardrail_hooks.custom_code.sandbox import (
build_sandbox_globals, compile_sandboxed,
)
# exercise the entry point with representative inputs before deploying
def smoke(custom_code: str) -> None:
g = build_sandbox_globals()
exec(compile_sandboxed(custom_code), g)
fn = g['apply_guardrail']
out = fn({'texts': ['hello'], 'messages': []}, {'metadata': {}}, 'request')
assert out is not None Try / catch
from litellm.proxy.guardrails.guardrail_hooks.custom_code.custom_code_guardrail import CustomCodeExecutionError
try:
inputs = await guardrail.apply_guardrail(inputs, request_data, input_type)
except CustomCodeExecutionError as e:
log.warning('custom guardrail crashed', guardrail=e.details.get('guardrail_name'),
input_type=e.details.get('input_type'), cause=repr(e.__cause__))
# deliberate policy choice: re-raise (fail closed) or proceed (fail open)
raise Prevention
- Inside custom_code, access inputs defensively and wrap sandbox HTTP calls in try/except
- Smoke-test apply_guardrail with realistic payloads (empty texts, missing metadata) in CI
- Decide and document fail-open vs fail-closed for each custom guardrail before rollout
- Read e.__cause__ first - it is the original exception from your function
When it happens
Trigger: Runtime bugs inside the user function on a hooked request: KeyError/TypeError from assuming an inputs shape, NameError for an undefined helper, arithmetic errors, or a sandbox HTTP primitive (http_get/http_post/http_request) raising on timeout/connection failure/status error.
Common situations: inputs['texts'][0] on an empty payload; calling the moderation endpoint without try/except and it 500s; assuming the primitive's return shape differs from the documented {success, status, body} dict; renaming a helper but not all call sites.
Related errors
- Custom code guardrail not compiled: {self._compile_error}
- Custom code guardrail requires a guardrail_name
- Custom code guardrail requires 'custom_code' in litellm_para
- Custom code guardrail not compiled
- Prisma client not initialized
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/2a027538c4e46a9a.
Report an issue: GitHub.