Azure OpenAI content filter triggered — content_filter policy blocked the request (2026) — Fix Guide (2026) | AI Error Hub
Home Providers Azure OpenAI Content filter blocked
Azure OpenAI Content Filter · Policy Severity: Medium HTTP 400

Azure OpenAI content_filter — filtered by policy, no completion returned

Content filter is Azure OpenAI's biggest behavioural difference from openai.com and the source of the most surprising production failures. This page maps every category, severity, and mitigation.

By Ahmed R. · Senior AI Infrastructure Engineer Published 2026-07-26 Verified 2026-07-26

Quick fix (TL;DR)

Resolution: Azure OpenAI runs input and output through a content filter across four categories (hate, sexual, violence, self-harm) at four severity levels (safe → high). When any category exceeds its configured threshold, the request returns with finish_reason: "content_filter" and no message.content. Fix by (a) reading content_filter_results to identify the triggering category, (b) creating a custom content filter policy in Azure AI Foundry with higher thresholds for legitimate use cases, and (c) handling the filtered state gracefully instead of treating it as a hard failure.

Real error messages you'll see

These are the exact strings returned by the Azure OpenAI service and its SDKs when this error occurs. Copy-paste-searching any of them should land on this page.

Python SDK — filtered response object
ChatCompletion(
    id="chatcmpl-...",
    choices=[
        Choice(
            finish_reason="content_filter",
            message=ChatCompletionMessage(content=None, role="assistant"),
            content_filter_results={
                "hate": {"filtered": False, "severity": "safe"},
                "self_harm": {"filtered": False, "severity": "safe"},
                "sexual": {"filtered": True, "severity": "medium"},
                "violence": {"filtered": False, "severity": "safe"}
            }
        )
    ]
)
Prompt filter — pre-generation block
openai.BadRequestError: Error code: 400 - {'error': {'code': 'content_filter', 'message': "The response was filtered due to the prompt triggering Azure OpenAI's content management policy. Please modify your prompt and retry.", 'innererror': {'code': 'ResponsibleAIPolicyViolation', 'content_filter_result': {'hate': {'filtered': False, 'severity': 'safe'}, 'jailbreak': {'filtered': True, 'detected': True}, ...}}}

Reference

The four content filter categories

CategoryWhat it detectsDefault actionCommon false positives
hateDiscriminatory language about protected groupsBlock at medium+Historical analysis, quoted material
sexualSexually explicit contentBlock at medium+Medical, health-education, LGBTQ+ contexts
violenceDescriptions of physical harmBlock at medium+News summaries, security research, fiction
self_harmSelf-injury contentBlock at medium+Mental health support, safety research
jailbreak (prompt shield)Attempts to bypass system promptBlock on detectionLegitimate role-play, adversarial testing
protected_material_textKnown copyrighted textBlock on detectionPublic domain, fair use, quoted excerpts
protected_material_codeVerbatim copies of public codeAnnotate, do not blockStandard boilerplate

Severity levels and default behaviour

SeverityMeaningDefault actionConfigurable in custom policy
safeNo concerning contentPassCannot be blocked
lowMild referencesPassCan be blocked
mediumModerate concernBlockCan be allowed
highExplicit / severeBlockCannot be allowed (except with approval)

Root causes, ranked by frequency

Based on developer reports across Azure OpenAI SDK forums, GitHub issues, and Microsoft Q&A during 2025–2026.

  • 28%
    Default policy is too strict for your use case. The default blocks at severity medium across all four categories. Medical, legal, security-research, and fiction workloads routinely hit medium false positives.
  • 20%
    Jailbreak detection triggering on legitimate role-play. Prompts like "You are a hacker helping me test my system" flag as jailbreak even when the intent is benign security research.
  • 16%
    User input containing quoted harmful content. Even when the user is quoting a news article for the model to summarise, the quoted content itself trips the filter.
  • 12%
    Streaming responses filtered mid-stream. Output that starts benign but drifts into a filtered category has its remaining tokens dropped; the client sees a truncated response.
  • 10%
    Language other than English. Non-English content is filtered less accurately; expect a higher false-positive rate on translated harmful content and false negatives on the reverse.
  • 8%
    Prompt shield / indirect prompt injection. Documents pasted into the prompt (RAG chunks) can carry jailbreak-style text and flag the whole request.
  • 4%
    Protected material — code matches on common boilerplate like Apache LICENSE files, causing annotation on outputs but not blocking.
  • 2%
    Region-specific filter differences. Filter models roll out in stages; a request that passes in East US may fail in Sweden Central until parity ships.

Fixes — copy-paste solutions

Fix #1

Read content_filter_results to detect and route filtered responses

Stop treating content_filter as a generic 400 — extract the category and severity.

The filtered response contains a content_filter_results block listing every category and its severity. Extract it to understand what tripped the filter, log for analysis, and return a specific message to the user instead of a generic error.

filter_handler.py
from openai import AzureOpenAI, BadRequestError
from typing import Any

client = AzureOpenAI(
    api_key="...", azure_endpoint="...", api_version="2024-10-21",
)

def call_with_filter_handling(messages: list) -> dict:
    try:
        response = client.chat.completions.create(
            model="gpt4o-prod",
            messages=messages,
            max_tokens=500,
        )
    except BadRequestError as e:
        # Prompt-side filter — request never ran
        body = e.body or {}
        inner = body.get("innererror", {})
        cf = inner.get("content_filter_result", {})
        triggered = [k for k, v in cf.items() if v.get("filtered") or v.get("detected")]
        return {
            "status": "prompt_filtered",
            "triggered_categories": triggered,
            "user_message": (
                "Your request could not be processed because it contains content "
                f"related to: {', '.join(triggered)}. Please rephrase and try again."
            ),
        }

    choice = response.choices[0]
    if choice.finish_reason == "content_filter":
        # Response-side filter — model generated something we cannot show
        cf = getattr(choice, "content_filter_results", {}) or {}
        triggered = [k for k, v in cf.items() if v.get("filtered")]
        severity = {k: v.get("severity") for k, v in cf.items() if v.get("filtered")}
        return {
            "status": "response_filtered",
            "triggered_categories": triggered,
            "severity": severity,
            "user_message": "The generated response was blocked. Try rephrasing your question.",
        }

    return {"status": "ok", "content": choice.message.content}
Log the triggered categories to your observability stack. Patterns in the triggering categories often reveal a prompt-engineering issue rather than a true policy violation — for example, translating user text into third-person before sending to the model reduces sexual-category false positives.
Fix #2

Create a custom content filter policy for higher-severity categories

Raise thresholds where your use case justifies it.

In Azure AI Foundry (portal), create a custom content filter with higher severity thresholds for categories that produce false positives in your domain. Attach the policy to your deployment. Requires approval for allowing high severity in any category.

apply_custom_filter.sh
# 1) Create the custom filter in Azure AI Foundry:
#    Portal -> Azure AI Foundry -> Your project -> Content Filters -> New
#
#    For a medical Q&A app, typical config:
#      hate:      block at medium
#      sexual:    block at high     (allow medium for reproductive-health topics)
#      violence:  block at high     (allow medium for injury descriptions)
#      self_harm: block at medium
#      jailbreak: block on detection
#      protected_material_text: annotate only (do not block)
#
# 2) Attach the filter to your deployment via CLI

az cognitiveservices account deployment update \
  --name my-aoai-resource \
  --resource-group my-rg \
  --deployment-name gpt4o-medical \
  --set properties.raiPolicyName="medical-qa-filter-v1"

# 3) Verify the attachment
az cognitiveservices account deployment show \
  --name my-aoai-resource -g my-rg \
  --deployment-name gpt4o-medical \
  --query "properties.raiPolicyName"
Approval required to allow content at high severity in any category. Submit the Modified Content Filters application form to Microsoft — reviews take 5-10 business days and require a documented use case.
Fix #3

Handle streaming filtered responses cleanly

Detect mid-stream filter events and surface a clean UI state.

When streaming, content_filter can arrive mid-stream. The client must watch for finish_reason: "content_filter" in the final chunk, discard or annotate the accumulated partial response, and signal the UI cleanly.

filter_stream.py
from openai import AzureOpenAI

client = AzureOpenAI(api_key="...", azure_endpoint="...", api_version="2024-10-21")

def stream_with_filter_awareness(messages: list):
    """Yields (event_type, payload) tuples: ('token', str) or ('filter', dict) or ('done', None)."""
    stream = client.chat.completions.create(
        model="gpt4o-prod",
        messages=messages,
        stream=True,
        max_tokens=500,
    )

    partial = []
    for chunk in stream:
        if not chunk.choices:
            continue
        choice = chunk.choices[0]

        # Filter fired mid-stream
        if choice.finish_reason == "content_filter":
            cf = getattr(choice, "content_filter_results", {}) or {}
            triggered = [k for k, v in cf.items() if v.get("filtered")]
            yield ("filter", {
                "triggered": triggered,
                "partial_length": len("".join(partial)),
                "message": "Response filtered mid-generation — content discarded.",
            })
            return

        if choice.delta and choice.delta.content:
            partial.append(choice.delta.content)
            yield ("token", choice.delta.content)

    yield ("done", None)

# UI-side usage
for event, payload in stream_with_filter_awareness([{"role": "user", "content": "..."}]):
    if event == "token":
        print(payload, end="", flush=True)
    elif event == "filter":
        print(f"\n\n[Filtered: {payload['triggered']}]")
    elif event == "done":
        print("\n[Complete]")
For UX, discard partial content when a filter fires — showing half a filtered response then removing it is worse than showing nothing. Better: buffer 3-5 tokens client-side and only paint them once the next chunk arrives clean.

Prevention checklist

Ship these seven safeguards once and this error stops appearing in your logs.

  • Always read content_filter_results instead of treating content_filter as an opaque failure.
  • Log triggered category + severity to your observability stack — patterns reveal prompt engineering issues.
  • For domain-specific use cases (medical, legal, security research), file for a custom content filter policy early — reviews take 5-10 business days.
  • Sanitise user-provided text before including it in prompts: strip HTML, escape harmful-looking quotes, and consider translating to third-person to reduce sexual/violence false positives.
  • For RAG applications, run the retrieved chunks through the content filter first via the Azure Content Safety API — cheaper than a full completion failure.
  • Set finish_reason handling in your streaming client to distinguish stop, length, content_filter, and tool_calls as separate UI states.
  • Run your prompt library through a filter probe weekly — Azure updates filter models and behaviour drifts.

Frequently asked questions

No. Azure OpenAI requires a content filter policy on every deployment. What you can do is create a custom policy with higher severity thresholds — up to and including "allow medium" in every category. Allowing high severity requires an approved Modified Content Filters application to Microsoft.
The filter is applied to input and output tokens as part of the standard request cost — there is no separate charge. Filtered requests are still billed for input tokens; they are not billed for output tokens when generation is aborted.
The prompt filter runs on the input before generation and returns 400 with content_filter_result. The response filter runs on generated output; the request completes with finish_reason=content_filter and no content. Both apply to the same four categories but detect different problems.
Fill in the Modified Content Filters application on the Azure OpenAI Limited Access page. You describe your use case, target industry, and mitigations you have in place. Approval typically takes 5-10 business days. Common approvals: medical, mental-health research, security research, red-teaming.
No. openai.com applies OpenAI's own moderation policy. Azure OpenAI applies Microsoft's Responsible AI content filter, which is stricter by default and has additional categories like protected_material and jailbreak detection. Prompts that work on openai.com can fail on Azure.

Get the weekly AI-error digest

New fixes, provider status recaps, and one deep tutorial — every Tuesday. 8,400+ engineers.