Short Answer
When a GPT model receives a request that violates the provider’s usage policy, it does not return an error. The API responds with HTTP 200,finish_reason is stop, and the content is a refusal written by the model itself, such as “I can’t help with that…”.
The response has no error code and no refusal category or severity. It has exactly the same structure as a normal answer and is billed like one. Looking at the status code and finish_reason alone, you cannot tell that the request was refused.
The Refusal Response Body
Below is a real non-streaming refusal from/v1/chat/completions (the content has been replaced with a neutral example):
Why There Is No Category
For policy-violating requests, the OpenAI chat API lets the model decide not to answer instead of returning an error. It does not tell you which category was hit (for example adult content, graphic violence, or self-harm), and it gives no severity. This is different from an error. With an error you get a non-200 status and anerror object. With a refusal you get a successful call whose content simply isn’t what you asked for.
Translation and Structured Output
Batch translation and extraction tasks usually ask the model for a fixed format, such as a JSON array. When a batch triggers a refusal, the model returns a plain sentence, so parsing it as JSON fails with errors likeUnrecognized token 'I' or Expecting value.
This is not an API format problem. The content of that batch was declined. Retrying the same batch unchanged usually gives the same result.
APIYI has enabled automatic failover for content safety on non-streaming requests. When one official route triggers a content filter, either on the prompt or on the generated output, the request is automatically retried on another official route, with no retry needed on your side. After failover most requests return a normal result; a small number may still be refused by the model itself, which is the case this page describes.
How to Detect and Handle It
1
Validate the output format first
If you asked for JSON, parse it as JSON; if you asked for a fixed number of items, check the count. If the format doesn’t match, treat the call as “no result” and don’t use the content as your output.
2
Then check whether it is a refusal
If the format doesn’t match, check whether the content is a short sentence starting with
I can't, Sorry, or similar. If so, it is almost certainly a refusal rather than the model drifting off format.3
Don't retry unchanged
Retrying the same content unchanged will most likely produce the same refusal, and each attempt is billed.
4
Split the batch to find the specific items
Resubmit the failed batch in smaller batches to find which items trigger the refusal; the rest usually complete normally. For the items that trigger it, adjust the wording and try again.
5
Archive failed cases, then decide whether to switch models
Keep an internal archive of failed cases (input, request time, request ID, returned content), review which kinds of content the refusals concentrate on, and then consider retrying that content with another model.
Streaming Requests
Once a streaming response starts, it can no longer be switched to another route, so automatic content safety failover only applies to non-streaming requests. With streaming you may see:- a short refusal whose last event has
finish_reasonset tocontent_filter; or - part of the content already delivered, ending with
finish_reason: "content_filter".
FAQ
Am I billed for a refusal?
Am I billed for a refusal?
Yes. A refusal is a successful call and is billed on actual input and output tokens, so avoid retrying the same content repeatedly.
Can refusals be turned off?
Can refusals be turned off?
No. Refusals are decided by the provider’s model under its usage policy. APIYI cannot turn them off or adjust how strict they are.
Why does the same content sometimes pass and sometimes get refused?
Why does the same content sometimes pass and sometimes get refused?
The model’s judgment has some randomness, and different official routes filter slightly differently, so borderline content may pass one time and be refused the next. Content that clearly violates the usage policy is refused consistently.
How can I get the refusal category?
How can I get the refusal category?
The OpenAI chat API does not return one. If your workflow needs categories, classify the content yourself before sending it, or sort the archived failed cases manually.
Related Docs
Response Handling
One parsing approach for streaming and non-streaming responses
How is content safety and compliance ensured?
Platform content safety and compliance policy