{"record":{"id":"70a4adf798eb1ee7","repo":"BerriAI/litellm","slug":"guardrail-guardrail-guardrail-name-scan-only-70a4ad","errorCode":null,"errorMessage":"Guardrail {guardrail['guardrail_name']}: scan_only_tool_results and skip_tool_message_in_guardrail are enabled together, which excludes every message from scanning, so no request content would ever be scanned. Remove one of the two.","messagePattern":"Guardrail (.+?): scan_only_tool_results and skip_tool_message_in_guardrail are enabled together, which excludes every message from scanning, so no request content would ever be scanned\\. Remove one of the two\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/proxy/guardrails/guardrail_registry.py","lineNumber":522,"sourceCode":"\n        if custom_guardrail_callback is not None:\n            for scoping_param in (\n                \"skip_system_message_in_guardrail\",\n                \"skip_tool_message_in_guardrail\",\n                \"scan_only_tool_results\",\n            ):\n                setattr(custom_guardrail_callback, scoping_param, getattr(litellm_params, scoping_param, None))\n            scan_only_tool_results_enabled: Final = effective_scan_only_tool_results_for_guardrail(\n                custom_guardrail_callback\n            )\n            if scan_only_tool_results_enabled and not custom_guardrail_callback.supports_scan_only_tool_results():\n                raise ValueError(\n                    f\"Guardrail {guardrail['guardrail_name']}: scan_only_tool_results is enabled, but this \"\n                    \"guardrail's role filtering never scans tool results, so no request content would ever \"\n                    \"be scanned. Remove scan_only_tool_results or the guardrail's role-filtering option.\"\n                )\n            if scan_only_tool_results_enabled and effective_skip_tool_message_for_guardrail(custom_guardrail_callback):\n                raise ValueError(\n                    f\"Guardrail {guardrail['guardrail_name']}: scan_only_tool_results and \"\n                    \"skip_tool_message_in_guardrail are enabled together, which excludes every message from \"\n                    \"scanning, so no request content would ever be scanned. Remove one of the two.\"\n                )\n            configured_run_in_parallel: Final[bool | None] = getattr(litellm_params, \"run_in_parallel\", None)\n            if configured_run_in_parallel is not None:\n                custom_guardrail_callback.run_in_parallel = bool(configured_run_in_parallel)\n\n        parsed_guardrail: Final = Guardrail(\n            guardrail_id=guardrail.get(\"guardrail_id\"),\n            guardrail_name=guardrail[\"guardrail_name\"],\n            litellm_params=litellm_params,\n            guardrail_info=guardrail.get(\"guardrail_info\"),\n        )\n\n        # store references to the guardrail in memory\n        self.IN_MEMORY_GUARDRAILS[guardrail_id] = parsed_guardrail\n        self.guardrail_id_to_custom_guardrail[guardrail_id] = custom_guardrail_callback","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/guardrails/guardrail_registry.py#L504-L540","documentation":"Guardrail init validation: scan_only_tool_results (restrict scanning to tool messages) and skip_tool_message_in_guardrail (exclude tool messages from scanning) are mutually exclusive - together they exclude every message, so no request content would ever be scanned. litellm rejects the combination at startup with this ValueError.","triggerScenarios":"A single guardrail entry with both scan_only_tool_results: true and skip_tool_message_in_guardrail: true in litellm_params.","commonSituations":"Flag accumulated over time as config evolved - one option added to reduce noise, later the other added for tool-result scanning; merging two guardrail configs into one.","solutions":["Decide the intent: either scan only tool results (keep scan_only_tool_results, drop skip_tool_message_in_guardrail) or exclude tool messages (the reverse)","Split into two guardrail entries if you need both behaviors for different hooks","Add a config lint step that rejects guardrail entries containing both flags"],"exampleFix":"# before\nlitellm_params:\n  guardrail: aim\n  scan_only_tool_results: true\n  skip_tool_message_in_guardrail: true\n\n# after\nlitellm_params:\n  guardrail: aim\n  scan_only_tool_results: true","handlingStrategy":"validation","validationCode":"# Hard rule: the two flags are mutually exclusive\nimport yaml\n\ncfg = yaml.safe_load(open('config.yaml'))\nfor g in cfg.get('guardrails', []):\n    lp = g.get('litellm_params') or {}\n    if lp.get('scan_only_tool_results') and lp.get('skip_tool_message_in_guardrail'):\n        raise SystemExit(\n            f\"{g.get('guardrail_name')}: pick ONE of scan_only_tool_results / skip_tool_message_in_guardrail\"\n        )","typeGuard":"def has_valid_scoping(litellm_params: dict) -> bool:\n    \"\"\"False when scoping flags would exclude every message from scanning.\"\"\"\n    return not (\n        bool(litellm_params.get('scan_only_tool_results'))\n        and bool(litellm_params.get('skip_tool_message_in_guardrail'))\n    )","tryCatchPattern":null,"preventionTips":["Add a config linter rule for mutually exclusive guardrail flags in CI","When changing scanning scope, remove obsolete flags instead of adding new ones on top","Split different scanning intents into separate guardrail entries"],"tags":["guardrail","config","conflicting-options","validation"],"backgroundTag":"conflicting-config-options","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}