If you generate images with GPT Image models (gpt-image-2, gpt-image-2.5) at any volume, you will eventually meet a frustrating error: HTTP 400, and a message saying your request was rejected by the safety system. No image, no partial output, and a prompt that looked perfectly reasonable to you.
This guide explains what that error actually is, what triggers it in practice, and how to tune prompts and reference images so it happens less. It is based on 30 days of production data from TokenLab's image API (August 19 – September 18, 2026), plus OpenAI's official image generation documentation. Where we quote numbers, they are aggregate platform statistics; no customer content is reproduced.
What the error actually is
GPT Image models filter every prompt, every input image, and every generated image against the provider's content policy. When a filter fires, the request fails with a 400 whose stable discriminator is the error code:
{
"error": {
"type": "image_generation_user_error",
"code": "moderation_blocked",
"moderation_details": {
"moderation_stage": "input",
"categories": ["sexual"]
}
}
}
Per the official documentation, moderation_details is optional and deliberately coarse: moderation_stage tells you whether the block came from your inputs (input) or from the generated image (output), and categories carries broad public labels such as harassment, self-harm, sexual, or violence. It never exposes internal classifier scores.
On TokenLab the same event shows up in two forms:
- Synchronous calls (
/v1/images/generations,/v1/images/edits) return HTTP 400 immediately. - Async tasks transition to
failedwith the message "The request was rejected by the safety system."
Either way, two operational facts matter. First, a moderation block is deterministic for the same content: retrying an unchanged request essentially never succeeds. Second, on TokenLab a moderation-blocked task is treated as a failed task and the pre-deducted quota is automatically refunded in full — you never pay for a blocked generation.
Thirty days of production data
Between August 19 and September 18, 2026, about 4.3% of GPT Image tasks on TokenLab — roughly one in 23 — were rejected by the upstream safety system. The distribution is not random; the blocked requests cluster tightly around a few patterns:
| Signal | Blocked tasks | All other tasks | Reading |
|---|---|---|---|
| Prompt mentions minors (child, kid, baby, "7-year-old", ...) | 79% | 33% | Strongest single predictor |
| Photorealistic-rendering wording ("photorealistic", "real human", "live-action") | 77% | 57% | Amplifier, especially with minors |
| Sexual-adjacent descriptors (nude, sexy, lingerie, body-focused wording) | 43% | 17% | Strong predictor |
| Generic action/violence words (battle, sword, explosion) | ~50% | ~50% | No predictive value on its own |
Three more findings from the same window:
- Reference images raise the risk. Tasks with input/reference images were blocked at 8.4%, versus 3.7% for text-only generation — more than double. Images are moderated as strictly as text.
- Long prompts fail more. Blocked prompts averaged about 3,600 characters, and over half exceeded 2,000 characters. Every extra clause is more surface area for a classifier.
- Retries never recovered. Every blocked task in the window ended in a terminal failed state; none succeeded by resubmitting the same input. And every one of them was refunded automatically.
The single most blocked workflow we observed: photorealistic character-design sheets of minors — "casting reference" style prompts that describe a child character with ultra-realistic rendering, precise body proportions, and clothing notes. Prompts combining minor-related vocabulary with photorealistic rendering were blocked at ~9.5%, 2.2× the baseline rate.
Five patterns that trigger blocks
Reading across the blocked population, nearly every rejection falls into one of these buckets:
- Photorealistic depictions of minors. Child or baby characters rendered as "a real human photographed in a studio", "ultra-photorealistic", "not CGI, not illustration". The combination of a minor and photorealism is the most heavily guarded boundary in image moderation, and it fires even when the intent is an innocent character sheet.
- Clothing- or body-focused wording around minors. Phrases like "unclothed collarbone-up close-up" (meant as a plain portrait crop) or detailed head-to-toe body-proportion measurements of a child character. Individually innocent, in aggregate they read as body-focused description of a minor.
- Sexualized descriptors of adult characters. Pose-, skin-, and underwear-focused vocabulary ("lingerie", "nude", "seductive pose") even in otherwise SFW compositions.
- Graphic gore anatomy. Horror and dark-fantasy prompts that describe rotting flesh, exposed organs, open wounds, or parasites in anatomical detail.
- Reference images of real people. Real photos of minors, images with high skin exposure, or celebrity-like faces used as edit inputs.
Two amplifiers make everything above more likely to trip: very long prompts (more text means more chances for a bad combination) and negative-word lists. A line like "no nudity, no sexual content, no gore" does not reassure the classifier — it repeats the concepts you want to avoid and adds them to the input. Describe what you want, not what you don't want.
The prompt tuning playbook
These are the rewrite moves that map to the data. (Examples are illustrative, not from customer traffic.)
1. Keep minors away from photorealism
If your story, comic, or game needs child characters, render them in a clearly stylized medium:
Before: "Ultra-photorealistic casting photo of a 7-year-old girl, real human
child photographed in a studio, detailed body proportions, collarbone-up
unclothed facial close-up ..."
After: "Storybook watercolor illustration of a young girl in Ming-dynasty
dress, shoulder-up portrait, round face, twin hair buns tied with cloth
ribbons, gentle expression, plain white background"
Change the medium (watercolor, 2D animation, 3D cartoon, picture-book style), drop the "real human / photographed" framing, and skip body measurements entirely. If you must describe clothing, describe what the character wears ("wearing a round-collar cloth jacket") rather than what they don't.
2. Delete negative-word lists
Replace "no nudity, no blood, no text, no watermark" with positive phrasing: "fully clothed", "clean composition", "plain background". Only keep negatives that don't name a restricted category (e.g. "no watermark" is fine; "no nudity" is not helping).
3. Trim the prompt
If you generate multi-panel character sheets, don't repeat the same style block in every panel description. One shared style sentence plus per-panel specifics keeps you under the surface-area threshold where accidental trigger combinations become likely.
4. Defuse gore with atmosphere, not anatomy
Before: "her body rotting, exposed skull, flesh, pustules and parasites ..."
After: "one half serene and maternal, the other half dissolving into shadow
and tidal mist, decay suggested through silhouette and lighting rather than
anatomical detail"
Dark fantasy survives moderation when the horror is carried by mood, lighting, and silhouette instead of tissue-level description.
5. Neutralize adult-content adjacency
For adult characters, swap body- and underwear-focused words for fashion and mood language: "evening gown" instead of "lingerie", "confident contrapposto" instead of "seductive pose".
Reference image hygiene
Because image inputs are moderated too — and in our data they more than double the block rate — treat reference images as part of the prompt:
- Prefer stylized references for minors. An illustration or 3D render of a child character is far safer input than a real photograph of a child, and usually works just as well for character consistency.
- Crop to what matters. If you need a face for identity consistency, upload the face crop, not a full-body beach photo. Less skin and less context means less classifier surface.
- Remove overlaid text and watermarks. Captions, meme text, and watermark strings on reference images are read as input text and can carry trigger words you forgot were there.
- Avoid real celebrity likenesses, both as reference images and as "in the style of <actor>" prompt text.
The moderation parameter
GPT Image models accept a moderation parameter with two values, per the official documentation:
auto(default): standard filtering that limits certain categories of potentially age-inappropriate content.low: less restrictive filtering.
TokenLab passes this parameter through on both /v1/images/generations and /v1/images/edits:
curl https://api.tokenlab.sh/v1/images/generations \
-H "Authorization: Bearer $TOKENLAB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"prompt": "Storybook watercolor illustration of a young girl in Ming-dynasty dress, shoulder-up portrait",
"size": "1024x1024",
"moderation": "low"
}'
Use low when your content is clearly benign but keeps getting flagged — stylized illustration work is the classic case. Two cautions: low is not off (illegal categories such as CSAM are always blocked), and it is a dial, not a guarantee — fix the prompt first, then reach for the parameter.
Handling blocks in code
The official guidance is explicit: image_generation_user_error failures are user-correctable and should not be retried without changing the request. Our data agrees — no blocked task in the 30-day window recovered by retrying an unchanged request. The right handling:
- Discriminate on
error.code, not the message text. Onlymoderation_blocked(andimage_generation_user_errorgenerally) means "fix the input". Rate limits and 5xx are still retryable. - Read the stage.
moderation_stage: "input"means rewrite the prompt or swap the reference image;"output"means the generated image itself was flagged — re-rolling with a slightly adjusted, de-risked prompt usually resolves it. - Keep the end-user message generic ("This request couldn't be completed due to content safety requirements") and log
moderation_detailsand the request ID for your own debugging and support. - Don't loop. Circuit-break after one moderation block per unique input; resubmitting identical content wastes latency and debugging time even though TokenLab refunds it.
Checklist
| Your situation | Likely trigger | Fix |
|---|---|---|
| Child character design sheet | Minor × photorealism | Stylized medium, no body measurements, positive clothing wording |
| Photorealistic adult portrait blocked | Sexualized descriptors | Fashion/mood wording; consider moderation="low" |
| Dark fantasy / horror creature | Gore anatomy | Atmosphere and silhouette instead of tissue detail |
| Edit with reference photo blocked | Real-person / skin-heavy input image | Crop tighter, use stylized reference, strip overlay text |
| Long multi-panel prompt blocked | Prompt surface area + negative lists | Dedupe boilerplate, delete negative-word lists |
| Benign stylized work still flagged | Classifier conservatism | moderation="low" |
FAQ
Do I pay for a blocked generation? No. On TokenLab, moderation-blocked tasks fail and the pre-deducted quota is refunded automatically and in full.
Does retrying the same prompt help? No. In 30 days of data, not a single blocked task succeeded on an unchanged retry. Change the input first.
Does moderation="low" disable safety filtering? No. It reduces restrictiveness; illegal content categories remain blocked regardless.
Are reference images really moderated? Yes — both the prompt and every input image are filtered, and tasks with reference images were blocked at more than twice the text-only rate in our data.
Can I see exactly which rule fired? Only at the coarse moderation_details.categories level, and only when the upstream includes it. Providers deliberately do not expose classifier internals.
Limitations
The statistics above are 30-day aggregates from TokenLab's production traffic and describe tendencies, not guarantees; moderation classifiers change over time, and the same prompt can be treated differently after an upstream update. The rewrite examples are illustrative templates, not customer data. Always validate against current behavior with a small test before a batch run.
To try these models, browse the image model catalog, review the async image generation guide for task lifecycle handling, and check docs.tokenlab.sh for the current request format.



