sigoden/aichat · error

Blocked due to safety

Error message

Blocked due to safety

What it means

Safety sentinel from the Gemini streaming path: the candidate's parts array contains a safety-blocking part instead of text or a function call, meaning the provider's safety filters refused to generate content for the prompt. It is a guard branch while iterating response parts — the input at fault is the prompt (or conversation history) tripping content filters.

Solutions

  1. Rephrase the prompt to avoid the content that triggered the filter and retry
  2. Enable/adjust safety settings on the request if the provider exposes them
  3. If safety blocks recur, inform the user that the provider refused the request rather than retrying blindly
  4. Trim or summarize conversation history that may be accumulating flagged content
Defensive patterns

Strategy: fallback

When it happens

Trigger: Thrown at src/client/vertexai.rs:229 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of sigoden/aichat@82976d349a (2026-09-09). Data as JSON: /api/errors/9db540952f8284db. Report an issue: GitHub.

Appendix: source

Thrown at src/client/vertexai.rs:229

            if let Some(parts) = data["candidates"][0]["content"]["parts"].as_array() {
                for (i, part) in parts.iter().enumerate() {
                    if let Some(text) = part["text"].as_str() {
                        if i > 0 {
                            handler.text("\n\n")?;
                        }
                        handler.text(text)?;
                    } else if let (Some(name), Some(args)) = (
                        part["functionCall"]["name"].as_str(),
                        part["functionCall"]["args"].as_object(),
                    ) {
                        handler.tool_call(ToolCall::new(name.to_string(), json!(args), None))?;
                    }
                }
            } else if let Some("SAFETY") = data["promptFeedback"]["blockReason"]
                .as_str()
                .or_else(|| data["candidates"][0]["finishReason"].as_str())
            {
                bail!("Blocked due to safety")
            }

            Ok(())
        };
        json_stream(res.bytes_stream(), handle).await?;
    }
    Ok(())
}

async fn embeddings(builder: RequestBuilder, _model: &Model) -> Result<EmbeddingsOutput> {
    let res = builder.send().await?;
    let status = res.status();
    let data: Value = res.json().await?;
    if !status.is_success() {
        catch_error(&data, status.as_u16())?;
    }
    let res_body: EmbeddingsResBody =
        serde_json::from_value(data).context("Invalid embeddings data")?;

View on GitHub (pinned to 82976d349a)