{"record":{"id":"35b3ca46c50c4f22","repo":"windmill-labs/windmill","slug":"worker-suffix-must-only-contain-ascii-letters-dig","errorCode":null,"errorMessage":"WORKER_SUFFIX must only contain ASCII letters, digits and underscores, got '{label}'","messagePattern":"WORKER_SUFFIX must only contain ASCII letters, digits and underscores, got '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-common/src/utils.rs","lineNumber":417,"sourceCode":"        None if EXIT_AFTER_N_JOBS.is_some() => create_stable_worker_suffix(hostname, index),\n        None => create_default_worker_suffix(hostname),\n    })\n}\n\n/// The operator's label only has to tell the worker processes of one host apart, so it is\n/// appended to the stable suffix rather than replacing it: the digest is what keeps two hosts\n/// whose names end on the same segment (`worker-east-1`, `worker-west-1`) from sharing an\n/// identity, and it already folds in the worker index. A `-` in the label would add a segment\n/// to the worker name, which [`retrieve_common_worker_prefix`] reads as the part to strip;\n/// rejected rather than rewritten, since the point of the label is that two different ones\n/// give two different names.\nfn create_labelled_worker_suffix(\n    hostname: &str,\n    label: &str,\n    index: usize,\n) -> anyhow::Result<String> {\n    if !label.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') {\n        return Err(anyhow::anyhow!(\n            \"WORKER_SUFFIX must only contain ASCII letters, digits and underscores, got '{label}'\"\n        ));\n    }\n    // The worker name is a `VARCHAR(255)` primary key and a component of the worker\n    // directory's path: a label long enough to blow either only surfaces at the initial ping,\n    // which the worker `expect`s.\n    if label.len() > MAX_WORKER_SUFFIX_LABEL_LEN {\n        return Err(anyhow::anyhow!(\n            \"WORKER_SUFFIX must be at most {MAX_WORKER_SUFFIX_LABEL_LEN} characters, got {}\",\n            label.len()\n        ));\n    }\n    Ok(format!(\n        \"{}_{label}\",\n        create_stable_worker_suffix(hostname, index)\n    ))\n}\n","sourceCodeStart":399,"sourceCodeEnd":435,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-common/src/utils.rs#L399-L435","documentation":"`create_labelled_worker_suffix` builds the per-worker name suffix from the WORKER_SUFFIX label. Windmill validates that the label consists solely of ASCII letters, digits and underscores, because it becomes part of the worker's database primary key and filesystem directory path; other characters could break naming or path handling. Any label containing spaces, dashes, dots, slashes, or non-ASCII characters triggers this error at worker startup.","triggerScenarios":"Starting a windmill worker with WORKER_SUFFIX set to a value containing characters outside [A-Za-z0-9_] — e.g. `WORKER_SUFFIX=my-worker`, `WORKER_SUFFIX=worker.eu`, `WORKER_SUFFIX=worker 1`, or a unicode label — when `resolve_worker_suffix` calls `create_labelled_worker_suffix`.","commonSituations":"Operators using hyphens (a common habit from container/host naming) in WORKER_SUFFIX; copy-pasting a hostname or docker container name (which contain dashes/dots) into WORKER_SUFFIX; templated deployments interpolating values with punctuation.","solutions":["Edit WORKER_SUFFIX to contain only ASCII letters, digits, and underscores (e.g. `my-worker` → `my_worker`).","Remove trailing/leading whitespace or quotes picked up from the env file or shell quoting.","If the label is generated from a hostname or container name, sanitize it by replacing non-alphanumeric characters with underscores before export.","Restart the worker; this error is fatal at startup by design."],"exampleFix":"// before (docker-compose env)\nWORKER_SUFFIX=worker-eu-1\n// after\nWORKER_SUFFIX=worker_eu_1","handlingStrategy":"validation","validationCode":"const label = process.env.WORKER_SUFFIX ?? \"\";\nif (!/^[A-Za-z0-9_]*$/.test(label)) {\n  throw new Error(`WORKER_SUFFIX '${label}' must only contain ASCII letters, digits and underscores`);\n}","typeGuard":"function isValidWorkerSuffixLabel(label) {\n  return typeof label === \"string\" && /^[A-Za-z0-9_]+$/.test(label);\n}","tryCatchPattern":"try {\n  startWorker({ suffix: process.env.WORKER_SUFFIX });\n} catch (e) {\n  if (String(e).includes(\"WORKER_SUFFIX must only contain\")) {\n    console.error(\"Sanitize WORKER_SUFFIX: replace [-. ] with _\");\n    process.env.WORKER_SUFFIX = process.env.WORKER_SUFFIX.replace(/[^A-Za-z0-9_]/g, \"_\");\n    return startWorker({ suffix: process.env.WORKER_SUFFIX });\n  }\n  throw e;\n}","preventionTips":["Use underscores, never hyphens or dots, in WORKER_SUFFIX.","Sanitize machine-generated labels (hostnames, container names) through .replace(/[^A-Za-z0-9_]/g, \"_\").","Add a deployment-time lint that asserts WORKER_SUFFIX matches ^[A-Za-z0-9_]+$.","Avoid shell/env quoting pitfalls that can inject whitespace into the value."],"tags":["configuration","worker","validation","env"],"backgroundTag":"invalid-config-value","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}