googleworkspace/cli · error · GwsError

Content blocked by Model Armor

Error message

Content blocked by Model Armor

What it means

When Model Armor sanitization is configured (--sanitize or GOOGLE_WORKSPACE_CLI_SANITIZE_TEMPLATE) and the mode is Block (GOOGLE_WORKSPACE_CLI_SANITIZE_MODE=block), every API response is inspected. If inspection finds a match (PII, secrets, harmful content per the template), the CLI prints a JSON object with the full sanitizationResult, then aborts the command with this error instead of letting the flagged content through.

Source

Thrown at crates/google-workspace-cli/src/executor.rs:278

            let text_to_check = serde_json::to_string(&json_val).unwrap_or_default();
            match crate::helpers::modelarmor::sanitize_text(template, &text_to_check).await {
                Ok(result) => {
                    let is_match = result.filter_match_state == "MATCH_FOUND";
                    if is_match {
                        eprintln!("⚠️  Model Armor: prompt injection detected (filterMatchState: MATCH_FOUND)");
                    }

                    if is_match && *sanitize_mode == crate::helpers::modelarmor::SanitizeMode::Block
                    {
                        let blocked = serde_json::json!({
                            "error": "Content blocked by Model Armor",
                            "sanitizationResult": serde_json::to_value(&result).unwrap_or_default(),
                        });
                        println!(
                            "{}",
                            serde_json::to_string_pretty(&blocked).unwrap_or_default()
                        );
                        return Err(GwsError::Other(anyhow::anyhow!(
                            "Content blocked by Model Armor"
                        )));
                    }

                    if let Some(obj) = json_val.as_object_mut() {
                        obj.insert(
                            "_sanitization".to_string(),
                            serde_json::to_value(&result).unwrap_or_default(),
                        );
                    }
                }
                Err(e) => {
                    eprintln!(
                        "⚠️  Model Armor sanitization failed: {}",
                        sanitize_for_terminal(&e.to_string())
                    );
                }
            }

View on GitHub (pinned to a3768d0e82)

Solutions

  1. Read the printed sanitizationResult JSON — it names the filter type and match details that caused the block
  2. If the content is legitimately safe, adjust the Model Armor template (narrow the detector) in GCP
  3. For warn-and-continue behavior, unset the block mode: GOOGLE_WORKSPACE_CLI_SANITIZE_MODE=warn (the default) — matches then annotate output with _sanitization instead of failing
  4. Otherwise rewrite the query/response handling to avoid retrieving the flagged content

Example fix

# before: hard stop on matches
$ export GOOGLE_WORKSPACE_CLI_SANITIZE_MODE=block
$ gws gmail users getProfile --params '{"userId":"me"}'
Error: Content blocked by Model Armor

# after: annotate instead of block
$ export GOOGLE_WORKSPACE_CLI_SANITIZE_MODE=warn
$ gws gmail users getProfile --params '{"userId":"me"}'   # output carries _sanitization field
Defensive patterns

Strategy: validation

Validate before calling

// Decide policy up front: only fail hard when block mode is explicitly required
fn sanitize_policy() -> SanitizePolicy {
    match std::env::var("GOOGLE_WORKSPACE_CLI_SANITIZE_MODE").as_deref() {
        Ok("block") => SanitizePolicy::Block,
        _ => SanitizePolicy::Warn, // default: annotate, do not abort
    }
}

Try / catch

match run_with_sanitization().await {
    Ok(v) => { /* proceed */ }
    Err(GwsError::Other(e)) if e.to_string() == "Content blocked by Model Armor" => {
        // parse the printed sanitizationResult JSON, decide: transform data, narrow the query, or escalate
    }
    Err(e) => { /* unrelated failure */ }
}

Prevention

When it happens

Trigger: Response body contains data matching a Model Armor template filter (e.g. an email/phone PII detector or a content classifier) while mode=block; the template was tightened after workflows were written, so previously-fine outputs now match; broad filter templates matching innocuous fields.

Common situations: Security policy requires block mode in shared environments; a template with overly broad regex/PII rules flags common content; listing operations (users, messages) returning personal data that triggers PII detectors.


AI-assisted analysis of googleworkspace/cli@a3768d0e82 (2026-08-16). Data as JSON: /api/errors/dfd20f39fa8fa5f2. Report an issue: GitHub.