zeroclaw-labs/zeroclaw · error

google_workspace.allowed_operations[{i}].sub_resource contai

Error message

google_workspace.allowed_operations[{i}].sub_resource contains invalid characters: {sub}

What it means

Config::validate() applies the same identifier rule to allowed_operations[].sub_resource as to resource: ASCII alphanumeric (camelCase allowed), '_' and '-' only. The sub-resource becomes a segment of the runtime tool key the allowlist matches on, so spaces, dots, slashes, or non-ASCII characters are rejected at config load time.

Source

Thrown at crates/zeroclaw-config/src/schema.rs:21889

                .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
            {
                anyhow::bail!(
                    "google_workspace.allowed_operations[{i}].resource contains invalid characters: {resource}"
                );
            }

            if let Some(ref sub_resource) = operation.sub_resource {
                let sub = sub_resource.trim();
                if sub.is_empty() {
                    anyhow::bail!(
                        "google_workspace.allowed_operations[{i}].sub_resource must not be empty when present"
                    );
                }
                if !sub
                    .chars()
                    .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
                {
                    anyhow::bail!(
                        "google_workspace.allowed_operations[{i}].sub_resource contains invalid characters: {sub}"
                    );
                }
            }

            if operation.methods.is_empty() {
                validation_bail!(
                    RequiredFieldEmpty,
                    format!("google_workspace.allowed_operations[{i}].methods"),
                    "google_workspace.allowed_operations[{i}].methods must not be empty"
                );
            }

            let mut seen_methods = std::collections::HashSet::new();
            for (j, method) in operation.methods.iter().enumerate() {
                let normalized = method.trim();
                if normalized.is_empty() {
                    anyhow::bail!(

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Use the bare sub-resource identifier ("attachments", "replies")
  2. Replace separators with '_' or '-','Drop path/version prefixes that belong to the URL, not the tool identifier

Example fix

# before
[[google_workspace.allowed_operations]]
service = "drive"
resource = "files"
sub_resource = "file.attachments"
methods = ["get"]

# after
[[google_workspace.allowed_operations]]
service = "drive"
resource = "files"
sub_resource = "attachments"
methods = ["get"]
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_gws_sub_resource(s: &str) -> bool {
    s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
}

Type guard

fn is_valid_gws_sub_resource(s: &str) -> bool {
    !s.is_empty() && s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
}

Try / catch

match config.validate() {
    Ok(()) => {}
    Err(e) if e.to_string().contains("sub_resource contains invalid characters") => {
        // replace dots/slashes with '_' or drop them; re-validate
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: An operation entry with sub_resource = "file attachments", sub_resource = "v2.items", or sub_resource = "café" being validated via Config::validate().

Common situations: Copying dotted names from Google API docs, translating REST path segments verbatim, or locale-specific characters slipping into hand-written config.

Understand the failure class

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/efb10783edcd7413. Report an issue: GitHub.