zeroclaw-labs/zeroclaw · error
google_workspace.allowed_services[{i}] contains invalid char
Error message
google_workspace.allowed_services[{i}] contains invalid characters: {normalized} What it means
Each entry in [google_workspace] allowed_services is normalized, then must consist solely of ASCII lowercase letters, digits, '_', or '-'. Unlike the OTP gated-actions check (which allows uppercase), this allowlist is strictly lowercase, so any uppercase letter, dot, space, or other punctuation fails with the offending value and index. The charset check runs before the duplicate check, so fix characters first.
Source
Thrown at crates/zeroclaw-config/src/schema.rs:21808
}
}
// Google Workspace allowed_services validation
let mut seen_gws_services = std::collections::HashSet::new();
for (i, service) in self.google_workspace.allowed_services.iter().enumerate() {
let normalized = service.trim();
if normalized.is_empty() {
validation_bail!(
RequiredFieldEmpty,
format!("google_workspace.allowed_services[{i}]"),
"google_workspace.allowed_services[{i}] must not be empty"
);
}
if !normalized
.chars()
.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '-')
{
anyhow::bail!(
"google_workspace.allowed_services[{i}] contains invalid characters: {normalized}"
);
}
if !seen_gws_services.insert(normalized.to_string()) {
anyhow::bail!(
"google_workspace.allowed_services contains duplicate entry: {normalized}"
);
}
}
// Build the effective allowed-services set for cross-validation.
// When the operator leaves allowed_services empty the tool falls back to
// DEFAULT_GWS_SERVICES; use the same constant here so validation is
// consistent in both cases.
let effective_services: std::collections::HashSet<&str> =
if self.google_workspace.allowed_services.is_empty() {
DEFAULT_GWS_SERVICES.iter().copied().collect()
} else {View on GitHub (pinned to 88bb9c8533)
Solutions
- Slugify the entry: lowercase, dots/underscores to '-', or '_' — "Calendar API" -> "calendar", "admin.directory" -> "admin_directory"
- Stick to the documented lowercase slug list for allowed services
- Re-run validation after each fix — the loop bails on the first invalid entry
Example fix
# before [google_workspace] allowed_services = ["Calendar", "drive.google.com"] # after [google_workspace] allowed_services = ["calendar", "drive"]
Defensive patterns
Strategy: validation
Validate before calling
fn valid_gws_service(name: &str) -> bool {
name.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '-')
}
fn gws_services_precheck(services: &[String]) -> Result<(), String> {
if let Some(bad) = services.iter().find(|s| !valid_gws_service(s)) {
return Err(format!("invalid allowed_services entry: {bad:?}"));
}
Ok(())
} Type guard
fn is_gws_service_slug(s: &str) -> bool {
!s.is_empty() && valid_gws_service(s)
} Try / catch
if let Err(err) = config.validate() {
if err.to_string().contains("google_workspace.allowed_services") && err.to_string().contains("invalid characters") {
// lowercase and slugify the entry at the reported index
}
} Prevention
- Translate Google API names to lowercase slugs at authoring time (Calendar API -> calendar)
- Lint allowed_services with the lowercase-only regex ^[a-z0-9_-]+$ before deploy
- Keep a canonical slug list next to the config for reviewers
When it happens
Trigger: Set allowed_services to entries like "Calendar" (uppercase), "drive.google.com" (dots), "sheets v4" (space), "Admin_Directory" (uppercase), or any non-slug string.
Common situations: Copying API names from Google's API directory where they appear as CamelCase product names or dotted Discovery names (`admin.directory`); mixing product names with service slugs; hand-editing without a reference list.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- google_workspace.allowed_services contains duplicate entry:
- cloud_ops.iac_tools must not be empty when cloud_ops is enab
- gateway.path_prefix contains invalid character '{bad}'; only
- risk_profiles.{profile_alias}.shell_env_passthrough[{i}] is
- security.otp.cache_valid_secs must be greater than or equal
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/08830bc8b6a04c4a.
Report an issue: GitHub.