BerriAI/litellm · error · ValueError

Guardrail {guardrail['guardrail_name']}: scan_only_tool_resu

Error message

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.

What it means

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.

Source

Thrown at litellm/proxy/guardrails/guardrail_registry.py:516

                guardrail_type=guardrail_type,
                litellm_params=litellm_params,
                config_file_path=config_file_path,
            )
        else:
            raise ValueError(f"Unsupported guardrail: {guardrail_type}")

        if custom_guardrail_callback is not None:
            for scoping_param in (
                "skip_system_message_in_guardrail",
                "skip_tool_message_in_guardrail",
                "scan_only_tool_results",
            ):
                setattr(custom_guardrail_callback, scoping_param, getattr(litellm_params, scoping_param, None))
            scan_only_tool_results_enabled: Final = effective_scan_only_tool_results_for_guardrail(
                custom_guardrail_callback
            )
            if scan_only_tool_results_enabled and not custom_guardrail_callback.supports_scan_only_tool_results():
                raise ValueError(
                    f"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."
                )
            if scan_only_tool_results_enabled and effective_skip_tool_message_for_guardrail(custom_guardrail_callback):
                raise ValueError(
                    f"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."
                )
            configured_run_in_parallel: Final[bool | None] = getattr(litellm_params, "run_in_parallel", None)
            if configured_run_in_parallel is not None:
                custom_guardrail_callback.run_in_parallel = bool(configured_run_in_parallel)

        parsed_guardrail: Final = Guardrail(
            guardrail_id=guardrail.get("guardrail_id"),
            guardrail_name=guardrail["guardrail_name"],
            litellm_params=litellm_params,

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Remove scan_only_tool_results from that guardrail's litellm_params
  2. Or remove/adjust the role-filtering option so tool results are actually scanned
  3. Re-read the guardrail integration's docs for which scoping combinations are valid

Example fix

# before
litellm_params:
  guardrail: aim
  scan_only_tool_results: true
  skip_system_message_in_guardrail: true
  skip_tool_message_in_guardrail: true

# after - pick one intent
# (a) scan everything:
litellm_params:
  guardrail: aim
# (b) scan only tool results:
litellm_params:
  guardrail: aim
  scan_only_tool_results: true
Defensive patterns

Strategy: validation

Validate before calling

# Reject scoping combinations that scan nothing
import yaml

cfg = yaml.safe_load(open('config.yaml'))
for g in cfg.get('guardrails', []):
    lp = g.get('litellm_params') or {}
    if lp.get('scan_only_tool_results') and lp.get('skip_tool_message_in_guardrail'):
        raise SystemExit('conflicting scoping: scan_only_tool_results + skip_tool_message_in_guardrail')
    if lp.get('scan_only_tool_results') and lp.get('skip_system_message_in_guardrail'):
        # only invalid for guardrails that never scan tool results - check the hook's docs
        print('warning: verify this guardrail scans tool results with skip_system enabled:', g.get('guardrail_name'))

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/01de680a767251d1. Report an issue: GitHub.