{"record":{"id":"fc9b339c93d2ef93","repo":"zeroclaw-labs/zeroclaw","slug":"google-workspace-allowed-operations-i-sub-resou","errorCode":null,"errorMessage":"google_workspace.allowed_operations[{i}].sub_resource must not be empty when present","messagePattern":"google_workspace\\.allowed_operations\\[(.+?)\\]\\.sub_resource must not be empty when present","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/schema.rs","lineNumber":21881,"sourceCode":"                    \"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() {\n                    anyhow::bail!(\n                        \"google_workspace.allowed_operations[{i}].sub_resource must not be empty when present\"\n                    );\n                }\n                if !sub\n                    .chars()\n                    .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')\n                {\n                    anyhow::bail!(\n                        \"google_workspace.allowed_operations[{i}].sub_resource contains invalid characters: {sub}\"\n                    );\n                }\n            }\n\n            if operation.methods.is_empty() {\n                validation_bail!(\n                    RequiredFieldEmpty,\n                    format!(\"google_workspace.allowed_operations[{i}].methods\"),\n                    \"google_workspace.allowed_operations[{i}].methods must not be empty\"","sourceCodeStart":21863,"sourceCodeEnd":21899,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/schema.rs#L21863-L21899","documentation":"When an allowed_operations entry sets the optional `sub_resource` key, Config::validate() requires the trimmed value to be non-empty. An empty Some(\"\") is worse than absent: it produces a malformed service.resource. tool key at runtime, so the validator rejects it at load time (the key is simply dropped if not present at all).","triggerScenarios":"An entry containing sub_resource = \"\" or sub_resource = \"   \" under [[google_workspace.allowed_operations]] when Config::validate() is called.","commonSituations":"Uncommenting a template line but leaving the placeholder empty; switching a resource-scoped entry to service-wide by blanking sub_resource instead of deleting the key; trailing-whitespace-only values from copy-paste.","solutions":["Delete the sub_resource key entirely if no sub-resource filter is wanted","Otherwise set it to the real sub-resource name (e.g. \"attachments\" for drive/files)","Trim accidental whitespace and re-validate the config"],"exampleFix":"# before\n[[google_workspace.allowed_operations]]\nservice = \"drive\"\nresource = \"files\"\nsub_resource = \"\"\nmethods = [\"get\"]\n\n# after\n[[google_workspace.allowed_operations]]\nservice = \"drive\"\nresource = \"files\"\nmethods = [\"get\"]","handlingStrategy":"validation","validationCode":"fn has_valid_sub_resource(op: &GwsOperation) -> bool {\n    op.sub_resource.as_deref().map(|s| !s.trim().is_empty()).unwrap_or(true)\n}","typeGuard":"fn sub_resource_ok(sub: Option<&str>) -> bool {\n    sub.map(|s| !s.trim().is_empty()).unwrap_or(true)\n}","tryCatchPattern":"match config.validate() {\n    Ok(()) => {}\n    Err(e) if e.to_string().contains(\"sub_resource must not be empty when present\") => {\n        // delete the key or give it a real value, then re-validate\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Prefer omitting optional keys over writing empty strings in TOML","When templating configs, delete placeholder keys rather than blanking them"],"tags":["config","google-workspace","validation","optional-field"],"backgroundTag":"required-config-field-empty","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}