{"record":{"id":"2a027538c4e46a9a","repo":"BerriAI/litellm","slug":"custom-code-guardrail-execution-failed-e","errorCode":null,"errorMessage":"Custom code guardrail execution failed: {e}","messagePattern":"Custom code guardrail execution failed: (.+?)","errorType":"exception","errorClass":"CustomCodeExecutionError","httpStatus":null,"severity":"error","filePath":"litellm/proxy/guardrails/guardrail_hooks/custom_code/custom_code_guardrail.py","lineNumber":258,"sourceCode":"                result = await result\n\n            # Process the result\n            return self._process_result(\n                result=result,\n                inputs=inputs,\n                request_data=request_data,\n                input_type=input_type,\n            )\n\n        except HTTPException:\n            # Re-raise HTTP exceptions (from block action)\n            raise\n        except ModifyResponseException:\n            # Pre-call block uses passthrough; must not wrap as execution error (500)\n            raise\n        except Exception as e:\n            verbose_proxy_logger.error(\"Custom code guardrail '%s' execution error: %s\", self.guardrail_name, e)\n            raise CustomCodeExecutionError(\n                f\"Custom code guardrail execution failed: {e}\",\n                details={\n                    \"guardrail_name\": self.guardrail_name,\n                    \"input_type\": input_type,\n                },\n            ) from e\n\n    def _prepare_safe_request_data(self, request_data: dict) -> dict[str, Any]:\n        \"\"\"\n        Prepare a safe subset of request_data for code execution.\n\n        This filters out sensitive information and provides only what's\n        needed for guardrail logic.\n\n        Args:\n            request_data: The full request data\n\n        Returns:","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/guardrails/guardrail_hooks/custom_code/custom_code_guardrail.py#L240-L276","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before: crashes on shape assumptions and HTTP failures\nasync def apply_guardrail(inputs, request_data, input_type):\n    text = inputs['texts'][0]\n    r = await http_post('https://mod.example/check', body={'text': text})\n    if r['body']['flagged']:\n        return block('flagged')\n    return allow()\n\n# after: guarded access, explicit failure policy\nasync def apply_guardrail(inputs, request_data, input_type):\n    for text in (inputs or {}).get('texts') or []:\n        try:\n            r = await http_post('https://mod.example/check', body={'text': text})\n        except Exception:\n            return allow()  # fail-open; use block(...) if you need fail-closed\n        if (r.get('body') or {}).get('flagged'):\n            return block('flagged by moderation API')\n    return allow()","handlingStrategy":"try-catch","validationCode":"from litellm.proxy.guardrails.guardrail_hooks.custom_code.sandbox import (\n    build_sandbox_globals, compile_sandboxed,\n)\n\n# exercise the entry point with representative inputs before deploying\ndef smoke(custom_code: str) -> None:\n    g = build_sandbox_globals()\n    exec(compile_sandboxed(custom_code), g)\n    fn = g['apply_guardrail']\n    out = fn({'texts': ['hello'], 'messages': []}, {'metadata': {}}, 'request')\n    assert out is not None","typeGuard":null,"tryCatchPattern":"from litellm.proxy.guardrails.guardrail_hooks.custom_code.custom_code_guardrail import CustomCodeExecutionError\ntry:\n    inputs = await guardrail.apply_guardrail(inputs, request_data, input_type)\nexcept CustomCodeExecutionError as e:\n    log.warning('custom guardrail crashed', guardrail=e.details.get('guardrail_name'),\n                input_type=e.details.get('input_type'), cause=repr(e.__cause__))\n    # deliberate policy choice: re-raise (fail closed) or proceed (fail open)\n    raise","preventionTips":["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"],"tags":["guardrails","custom-code","runtime-error","user-code","litellm-proxy"],"backgroundTag":"user-guardrail-code-runtime-error","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}