litellm - 💡(How to fix) Fix panw_prisma_airs: string-valued `timeout` produces misleading "Security scan failed" 500 [2 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

panw_prisma_airs.py:491 - PANW Prisma AIRS: Unexpected error: '<=' not supported between instances of 'str' and 'int'

Root Cause

panw_prisma_airs.PanwPrismaAirsHandler.__init__ stores self.timeout = timeout without coercion. The string survives to the httpx.AsyncClient.post(..., timeout=self.timeout) call at line 376, which raises.

There used to be a float() cast in litellm/proxy/guardrails/guardrail_initializers.py:220, but that initializer is no longer the active path. The package-local initializer at litellm/proxy/guardrails/guardrail_hooks/panw_prisma_airs/__init__.py:20 is now the registered initializer, and it just splats litellm_params.model_dump(exclude_unset=True) into the handler. Because timeout is not declared on BaseLitellmParams, it lives in Pydantic's extras (model_config = ConfigDict(extra="allow")) and Pydantic does not coerce extras.

So both write paths (UI form, raw YAML) and both init paths converge on storing whatever the user typed, including a string.

Fix Action

Fixed

Code Example

HTTP 500
{
  "error": {
    "message": "Security scan failed - request blocked for safety",
    "type": "guardrail_scan_error",
    "code": "panw_prisma_airs_scan_failed",
    "guardrail": "<your-guardrail-name>",
    "category": "api_error"
  }
}

---

# litellm-config.yaml
model_list:
  - model_name: gpt-4
    litellm_params:
      model: anthropic/claude-haiku-4-5-20251001
      api_key: os.environ/ANTHROPIC_API_KEY
      guardrails: [airs]

guardrails:
  - guardrail_name: airs
    litellm_params:
      guardrail: panw_prisma_airs
      mode: pre_call
      api_key: os.environ/AIRS_API_KEY
      profile_name: os.environ/AIRS_API_PROFILE_NAME
      api_base: https://service.api.aisecurity.paloaltonetworks.com
      timeout: "30"        # string. Same value as int (timeout: 30) works fine.
      default_on: true

---

curl -sS http://localhost:4000/v1/chat/completions \
  -H "Authorization: Bearer sk-1234" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4","messages":[{"role":"user","content":"hello"}]}'

---

panw_prisma_airs.py:491 - PANW Prisma AIRS: Unexpected error:
  '<=' not supported between instances of 'str' and 'int'

---

self.timeout = float(timeout) if timeout is not None else 10.0
RAW_BUFFERClick to expand / collapse

What happens

Configuring a panw_prisma_airs guardrail with timeout as a string (which is what the LiteLLM dashboard writes to the DB when you fill in the Timeout field) causes every request through that guardrail to fail with:

HTTP 500
{
  "error": {
    "message": "Security scan failed - request blocked for safety",
    "type": "guardrail_scan_error",
    "code": "panw_prisma_airs_scan_failed",
    "guardrail": "<your-guardrail-name>",
    "category": "api_error"
  }
}

The error message suggests AIRS itself rejected the content. It did not. No request was sent to AIRS at all. The string timeout value bubbles into httpx, which tries timeout <= 0 and raises TypeError, which the broad except Exception in panw_prisma_airs.py swallows and reports as category: "api_error".

Why this is hard to spot in production

  • The error string mentions "safety" and "blocked", so operators assume a content violation.
  • The guardrail returns _is_transient: true, suggesting a recoverable AIRS-side issue.
  • Total latency on the failed call is ~1ms, which looks like a fast AIRS reject rather than a local exception.
  • The AIRS Activity Log in Strata Cloud Manager shows zero scan attempts (because none were sent), which sends operators down an API-key / profile-linkage rabbit hole on the AIRS side rather than back to the proxy config.

Reproduction

LiteLLM v1.85.0 (also reproduced on v1.83.14-stable).

# litellm-config.yaml
model_list:
  - model_name: gpt-4
    litellm_params:
      model: anthropic/claude-haiku-4-5-20251001
      api_key: os.environ/ANTHROPIC_API_KEY
      guardrails: [airs]

guardrails:
  - guardrail_name: airs
    litellm_params:
      guardrail: panw_prisma_airs
      mode: pre_call
      api_key: os.environ/AIRS_API_KEY
      profile_name: os.environ/AIRS_API_PROFILE_NAME
      api_base: https://service.api.aisecurity.paloaltonetworks.com
      timeout: "30"        # string. Same value as int (timeout: 30) works fine.
      default_on: true
curl -sS http://localhost:4000/v1/chat/completions \
  -H "Authorization: Bearer sk-1234" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4","messages":[{"role":"user","content":"hello"}]}'

Result: HTTP 500 Security scan failed - request blocked for safety.

With timeout: 30 (no quotes) the same config works.

Underlying error (from LITELLM_LOG=DEBUG)

panw_prisma_airs.py:491 - PANW Prisma AIRS: Unexpected error:
  '<=' not supported between instances of 'str' and 'int'

Root cause

panw_prisma_airs.PanwPrismaAirsHandler.__init__ stores self.timeout = timeout without coercion. The string survives to the httpx.AsyncClient.post(..., timeout=self.timeout) call at line 376, which raises.

There used to be a float() cast in litellm/proxy/guardrails/guardrail_initializers.py:220, but that initializer is no longer the active path. The package-local initializer at litellm/proxy/guardrails/guardrail_hooks/panw_prisma_airs/__init__.py:20 is now the registered initializer, and it just splats litellm_params.model_dump(exclude_unset=True) into the handler. Because timeout is not declared on BaseLitellmParams, it lives in Pydantic's extras (model_config = ConfigDict(extra="allow")) and Pydantic does not coerce extras.

So both write paths (UI form, raw YAML) and both init paths converge on storing whatever the user typed, including a string.

Why the UI is the common trigger

The dashboard's guardrail settings form sends the Timeout field as a JSON string. The REST handler writes it through to the DB unchanged, and on next proxy boot the handler comes up with self.timeout = "30".

Suggested fix

Two-part:

  1. Defensive cast in PanwPrismaAirsHandler.__init__ so every init path is safe:

    self.timeout = float(timeout) if timeout is not None else 10.0
  2. Declare timeout on BaseLitellmParams with a mode="before" validator that coerces strings to float. Fixes the class of bug for any other guardrail provider that pulls timeout from litellm_params.

Happy to send the PR. Will include a regression test that round-trips a string-valued timeout through the handler.

Environment

  • LiteLLM: 1.85.0 (docker ghcr.io/berriai/litellm:main-stable, also tested on 1.83.14-stable)
  • Python: 3.13
  • httpx: bundled
  • Backend tested: Anthropic, Azure OpenAI, Bedrock (failure is identical across all three because it occurs before the LLM call)

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

litellm - 💡(How to fix) Fix panw_prisma_airs: string-valued `timeout` produces misleading "Security scan failed" 500 [2 pull requests]