{"record":{"id":"1dab05e8a166952b","repo":"zeroclaw-labs/zeroclaw","slug":"google-workspace-allowed-operations-i-resource","errorCode":null,"errorMessage":"google_workspace.allowed_operations[{i}].resource must not be empty","messagePattern":"google_workspace\\.allowed_operations\\[(.+?)\\]\\.resource must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/schema.rs","lineNumber":21847,"sourceCode":"                    .iter()\n                    .map(|s| s.trim())\n                    .collect()\n            };\n\n        let mut seen_gws_operations = std::collections::HashSet::new();\n        for (i, operation) in self.google_workspace.allowed_operations.iter().enumerate() {\n            let service = operation.service.trim();\n            let resource = operation.resource.trim();\n\n            if service.is_empty() {\n                validation_bail!(\n                    RequiredFieldEmpty,\n                    format!(\"google_workspace.allowed_operations[{i}].service\"),\n                    \"google_workspace.allowed_operations[{i}].service must not be empty\"\n                );\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            }","sourceCodeStart":21829,"sourceCodeEnd":21865,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/schema.rs#L21829-L21865","documentation":"Config::validate() rejects any [[google_workspace.allowed_operations]] entry whose `resource` field is empty or whitespace-only. The resource segment (e.g. `calendarList`, `files`) is a required part of the service.resource[.sub_resource] tool identifier that the runtime allowlist matches against, so an empty value could never authorize anything and is refused at config load time instead of silently dead-matching.","triggerScenarios":"Loading or validating a zeroclaw config in which an entry under [[google_workspace.allowed_operations]] has resource = \"\" (or only whitespace), e.g. at daemon startup, config reload, or any code path that calls Config::validate() on a deserialized Config.","commonSituations":"Copy-pasting an operation template and forgetting to fill in resource; scaffolding configs generated with placeholder empty strings; intending a service-wide grant (no resource filter), which this schema does not support.","solutions":["Set resource to a real Google API resource name for that service (e.g. \"calendarList\" for service \"calendar\", \"files\" for \"drive\")","Remove the whole [[google_workspace.allowed_operations]] block if you do not need that grant","Re-run the config validation command after the edit to confirm the entry passes"],"exampleFix":"# before\n[[google_workspace.allowed_operations]]\nservice = \"calendar\"\nresource = \"\"\nmethods = [\"list\"]\n\n# after\n[[google_workspace.allowed_operations]]\nservice = \"calendar\"\nresource = \"calendarList\"\nmethods = [\"list\"]","handlingStrategy":"validation","validationCode":"// Rust: pre-flight the field before calling Config::validate()\nfn has_gws_resource(op: &zeroclaw_config::schema::GwsOperation) -> bool {\n    !op.resource.trim().is_empty()\n}\n// for op in &config.google_workspace.allowed_operations {\n//     assert!(has_gws_resource(op), \"missing resource on operation\");\n// }","typeGuard":"fn is_non_empty_resource(v: &str) -> bool { !v.trim().is_empty() }","tryCatchPattern":"// validate() returns anyhow::Result; branch on the message prefix\nmatch config.validate() {\n    Ok(()) => {}\n    Err(e) if e.to_string().starts_with(\"google_workspace.allowed_operations\") => {\n        eprintln!(\"bad google_workspace config: {e}\"); // fix the TOML, do not retry\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Generate google_workspace config from a template that pre-fills service/resource/method with real values","Run the config-check CLI entry point in CI for every config change","Treat empty string placeholders as errors in editor linting (editorconfig / TOML linter)"],"tags":["config","google-workspace","validation","toml"],"backgroundTag":"required-config-field-empty","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}