{"record":{"id":"01de680a767251d1","repo":"BerriAI/litellm","slug":"guardrail-guardrail-guardrail-name-scan-only","errorCode":null,"errorMessage":"Guardrail {guardrail['guardrail_name']}: scan_only_tool_results is enabled, but this guardrail's role filtering never scans tool results, so no request content would ever be scanned. Remove scan_only_tool_results or the guardrail's role-filtering option.","messagePattern":"Guardrail (.+?): scan_only_tool_results is enabled, but this guardrail's role filtering never scans tool results, so no request content would ever be scanned\\. Remove scan_only_tool_results or the guardrail's role-filtering option\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/proxy/guardrails/guardrail_registry.py","lineNumber":516,"sourceCode":"                guardrail_type=guardrail_type,\n                litellm_params=litellm_params,\n                config_file_path=config_file_path,\n            )\n        else:\n            raise ValueError(f\"Unsupported guardrail: {guardrail_type}\")\n\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,","sourceCodeStart":498,"sourceCodeEnd":534,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/guardrails/guardrail_registry.py#L498-L534","documentation":"After building a guardrail callback, litellm cross-checks message-scoping options: if scan_only_tool_results is enabled but the guardrail's role-filtering configuration means tool results are never scanned (supports_scan_only_tool_results() returns False), the config would silently scan nothing. litellm fails fast at init with this ValueError instead of letting the guardrail be a no-op.","triggerScenarios":"A guardrail entry combining scan_only_tool_results: true with role-filtering options (skip_system_message_in_guardrail, skip_tool_message_in_guardrail, or guardrail-specific role filters) that exclude tool messages from scanning.","commonSituations":"Copy-pasted guardrail config where scoping flags from another integration were left in; tightening a guardrail to user-message-only and then enabling scan_only_tool_results without removing the old filters.","solutions":["Remove scan_only_tool_results from that guardrail's litellm_params","Or remove/adjust the role-filtering option so tool results are actually scanned","Re-read the guardrail integration's docs for which scoping combinations are valid"],"exampleFix":"# before\nlitellm_params:\n  guardrail: aim\n  scan_only_tool_results: true\n  skip_system_message_in_guardrail: true\n  skip_tool_message_in_guardrail: true\n\n# after - pick one intent\n# (a) scan everything:\nlitellm_params:\n  guardrail: aim\n# (b) scan only tool results:\nlitellm_params:\n  guardrail: aim\n  scan_only_tool_results: true","handlingStrategy":"validation","validationCode":"# Reject scoping combinations that scan nothing\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('conflicting scoping: scan_only_tool_results + skip_tool_message_in_guardrail')\n    if lp.get('scan_only_tool_results') and lp.get('skip_system_message_in_guardrail'):\n        # only invalid for guardrails that never scan tool results - check the hook's docs\n        print('warning: verify this guardrail scans tool results with skip_system enabled:', g.get('guardrail_name'))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Model allowed scoping-flag combinations per guardrail type in a config schema","Document intent in a comment above each scoping flag so future edits keep one goal","Treat startup validation errors like this as a gift: never bypass them"],"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-14T00:17:10.932Z"}