{"record":{"id":"3d8b06fadff9cb89","repo":"BerriAI/litellm","slug":"custom-code-must-define-an-apply-guardrail-funct","errorCode":null,"errorMessage":"Custom code must define an 'apply_guardrail' function. Expected signature: apply_guardrail(inputs, request_data, input_type)","messagePattern":"Custom code must define an 'apply_guardrail' function\\. Expected signature: apply_guardrail\\(inputs, request_data, input_type\\)","errorType":"exception","errorClass":"CustomCodeCompilationError","httpStatus":null,"severity":"error","filePath":"litellm/proxy/guardrails/guardrail_hooks/custom_code/custom_code_guardrail.py","lineNumber":156,"sourceCode":"    @classmethod\n    def get_supported_event_hooks(cls) -> list[GuardrailEventHooks]:\n        return [\n            GuardrailEventHooks.pre_call,\n            GuardrailEventHooks.during_call,\n            GuardrailEventHooks.post_call,\n            GuardrailEventHooks.pre_mcp_call,\n            GuardrailEventHooks.during_mcp_call,\n            GuardrailEventHooks.logging_only,\n        ]\n\n    def _do_compile(self) -> None:\n        \"\"\"Internal compilation method without lock. Expected to run inside _compile_lock.\"\"\"\n        exec_globals: Final = build_sandbox_globals()\n        compiled: Final = compile_sandboxed(self.custom_code)\n        exec(compiled, exec_globals)  # noqa: S102\n\n        if \"apply_guardrail\" not in exec_globals:\n            raise CustomCodeCompilationError(\n                \"Custom code must define an 'apply_guardrail' function. \"\n                \"Expected signature: apply_guardrail(inputs, request_data, input_type)\"\n            )\n\n        apply_fn: Final = exec_globals[\"apply_guardrail\"]\n        if not callable(apply_fn):\n            raise CustomCodeCompilationError(\"'apply_guardrail' must be a callable function\")\n\n        self._compiled_function = apply_fn\n\n    def _compile_custom_code(self) -> None:\n        \"\"\"\n        Compile the custom code and extract the apply_guardrail function.\n\n        The code runs in a sandboxed environment with only the allowed primitives.\n        \"\"\"\n        with self._compile_lock:\n            if self._compiled_function is not None:","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/guardrails/guardrail_hooks/custom_code/custom_code_guardrail.py#L138-L174","documentation":"CustomCodeCompilationError raised after the sandboxed custom code compiled and executed but no top-level apply_guardrail name exists in the execution globals. The custom-code guardrail contract requires an entry point with signature apply_guardrail(inputs, request_data, input_type); syntax-valid code that never defines it (or misspells it) fails here.","triggerScenarios":"custom_code defines the function under a different name (apply_guardrails plural, run_guardrail, check) or only defines helpers/constants; raised on first compile — at guardrail instantiation or on the first hooked request.","commonSituations":"Porting snippets from other frameworks with a different entry-point name; refactoring renames the function; generated code emits a differently named wrapper.","solutions":["Define def apply_guardrail(inputs, request_data, input_type): at the top level of custom_code","Check the exact spelling — singular, underscore-separated, case-sensitive","Ensure every path in the function returns allow()/block(...)/modify(...) rather than falling through"],"exampleFix":"# before: wrong entry-point name\ndef check_prompts(inputs):\n    return allow()\n\n# after\ndef apply_guardrail(inputs, request_data, input_type):\n    for text in inputs.get('texts') or []:\n        if 'secret-project' in text:\n            return block('confidential term detected')\n    return allow()","handlingStrategy":"validation","validationCode":"from litellm.proxy.guardrails.guardrail_hooks.custom_code.sandbox import (\n    build_sandbox_globals, compile_sandboxed,\n)\n\ndef preflight(custom_code: str) -> None:\n    g = build_sandbox_globals()\n    exec(compile_sandboxed(custom_code), g)\n    assert callable(g.get('apply_guardrail')), 'custom_code must define callable apply_guardrail(inputs, request_data, input_type)'","typeGuard":"def has_entrypoint(exec_globals: dict) -> bool:\n    return callable(exec_globals.get('apply_guardrail'))","tryCatchPattern":"from litellm.proxy.guardrails.guardrail_hooks.custom_code.custom_code_guardrail import CustomCodeCompilationError\ntry:\n    guardrail = CustomCodeGuardrail(guardrail_name='g', custom_code=src, event_hook='pre_call', default_on=True)\n    guardrail._compile_custom_code()\nexcept CustomCodeCompilationError as e:\n    raise SystemExit(f'custom_code rejected: {e}') from e","preventionTips":["Run the sandbox preflight (compile + exec + callable check) in CI for every custom_code change","Start from the documented template def apply_guardrail(inputs, request_data, input_type) and never rename it"],"tags":["guardrails","custom-code","sandbox","entrypoint","validation"],"backgroundTag":"sandbox-entrypoint-missing","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}