{"record":{"id":"78c4a8c83685781a","repo":"zeroclaw-labs/zeroclaw","slug":"google-workspace-allowed-operations-i-service-c","errorCode":null,"errorMessage":"google_workspace.allowed_operations[{i}].service contains invalid characters: {service}","messagePattern":"google_workspace\\.allowed_operations\\[(.+?)\\]\\.service contains invalid characters: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/schema.rs","lineNumber":21862,"sourceCode":"                );\n            }\n            if resource.is_empty() {\n                anyhow::bail!(\n                    \"google_workspace.allowed_operations[{i}].resource must not be empty\"\n                );\n            }\n\n            if !effective_services.contains(service) {\n                anyhow::bail!(\n                    \"google_workspace.allowed_operations[{i}].service '{service}' is not in the \\\n                     effective allowed_services; this entry can never match at runtime\"\n                );\n            }\n            if !service\n                .chars()\n                .all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '-')\n            {\n                anyhow::bail!(\n                    \"google_workspace.allowed_operations[{i}].service contains invalid characters: {service}\"\n                );\n            }\n            // Unlike service IDs, resource/sub_resource/method names are camelCase\n            // in the Google APIs (calendarList, quickAdd, batchUpdate), so\n            // uppercase must be accepted here and in the runtime tool check.\n            if !resource\n                .chars()\n                .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')\n            {\n                anyhow::bail!(\n                    \"google_workspace.allowed_operations[{i}].resource contains invalid characters: {resource}\"\n                );\n            }\n\n            if let Some(ref sub_resource) = operation.sub_resource {\n                let sub = sub_resource.trim();\n                if sub.is_empty() {","sourceCodeStart":21844,"sourceCodeEnd":21880,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/schema.rs#L21844-L21880","documentation":"Config::validate() enforces an ID-style character set for allowed_operations[].service: only ASCII lowercase letters, ASCII digits, '_' and '-' are accepted. Google service IDs are lowercase identifiers (calendar, gmail, drive, chat), so any uppercase letter, space, dot, or non-ASCII character is rejected at load time before the runtime allowlist is built.","triggerScenarios":"An operation entry with service = \"Calendar\", service = \"google calendar\", service = \"gcal.0\", or any value containing uppercase/whitespace/punctuation, hit when the config is deserialized and Config::validate() runs.","commonSituations":"Copy-pasting display names or product names from Google's console (\"Google Calendar\"), using the camelCase habit that IS valid for resource/method fields but not for service IDs, or trailing spaces from manual editing.","solutions":["Rewrite the service ID in lowercase snake/kebab form (\"calendar\", \"gmail\", \"drive\")","Remove surrounding whitespace and dots/dashes used as decoration","Cross-check the corrected value against the allowed_services list to also satisfy the membership check"],"exampleFix":"# before\n[[google_workspace.allowed_operations]]\nservice = \"Calendar\"\nresource = \"calendarList\"\nmethods = [\"list\"]\n\n# after\n[[google_workspace.allowed_operations]]\nservice = \"calendar\"\nresource = \"calendarList\"\nmethods = [\"list\"]","handlingStrategy":"validation","validationCode":"fn is_valid_gws_service_id(s: &str) -> bool {\n    !s.trim().is_empty()\n        && s.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '-')\n}","typeGuard":"fn is_valid_gws_service_id(s: &str) -> bool {\n    s.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '-')\n}","tryCatchPattern":"match config.validate() {\n    Ok(()) => {}\n    Err(e) if e.to_string().contains(\"service contains invalid characters\") => {\n        // lowercase the service id in the TOML source and re-validate\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Keep a canonical list of Google service IDs (calendar, gmail, drive, chat, ...) and copy from it","Never reuse resource-style camelCase for service IDs","Lint config in CI so a hand-edit cannot ship without validate() passing"],"tags":["config","google-workspace","validation","naming"],"backgroundTag":"config-field-invalid-characters","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}