zeroclaw-labs/zeroclaw · error

google_workspace.allowed_operations[{i}].resource contains i

Error message

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

What it means

Config::validate() checks that allowed_operations[].resource contains only ASCII alphanumeric characters (both cases), '_' and '-'. Unlike service IDs, camelCase is deliberately accepted here because Google API resource names are camelCase (calendarList, quickUpdate); spaces, dots, slashes and other punctuation are rejected so the resource can be matched unambiguously against runtime tool identifiers.

Source

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

                     effective allowed_services; this entry can never match at runtime"
                );
            }
            if !service
                .chars()
                .all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '-')
            {
                anyhow::bail!(
                    "google_workspace.allowed_operations[{i}].service contains invalid characters: {service}"
                );
            }
            // Unlike service IDs, resource/sub_resource/method names are camelCase
            // in the Google APIs (calendarList, quickAdd, batchUpdate), so
            // uppercase must be accepted here and in the runtime tool check.
            if !resource
                .chars()
                .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}"
                    );

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Use the bare camelCase resource name from the Google API ("calendarList", "files", "messages")
  2. Replace spaces with '_' or '-' if you need a separator, or drop path prefixes entirely
  3. Verify the value against the service's API surface so the runtime check can actually match

Example fix

# before
[[google_workspace.allowed_operations]]
service = "calendar"
resource = "calendar/v3/calendarList"
methods = ["list"]

# after
[[google_workspace.allowed_operations]]
service = "calendar"
resource = "calendarList"
methods = ["list"]
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

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

Try / catch

match config.validate() {
    Ok(()) => {}
    Err(e) if e.to_string().contains("resource contains invalid characters") => {
        // strip path segments/dots; keep the bare camelCase resource name
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: An operation entry with resource = "calendar list", resource = "files.attachments", or resource = "a/b" in the config file, surfaced when Config::validate() runs at startup or config check.

Common situations: Transcribing REST paths ("calendar/v3/calendarList") or dot-separated names from API documentation instead of the bare resource name; inserting spaces while hand-editing long TOML arrays.

Understand the failure class

Related errors


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