windmill-labs/windmill · error · Error
Fork workspace id \`${id}\` is invalid: ${reason}. Choose a
Error message
Fork workspace id \`${id}\` is invalid: ${reason}. Choose a shorter or simpler name/id. What it means
`validateForkWorkspaceId` pre-validates the generated `wm-fork-<slug>` workspace id (max 50 chars, simple slug) before any backend call. This early rejection exists because later steps (existsWorkspace, datatable cloning, branch creation) are not cleaned up on a late backend rejection.
Source
Thrown at cli/src/commands/workspace/fork.ts:500
*/
function branchToForkId(branch: string): string {
const slug = branch
.replace(/[^a-zA-Z0-9_-]+/g, "-")
.replace(/^-+|-+$/g, "")
.slice(0, MAX_FORK_ID_SLUG)
.replace(/-+$/g, ""); // re-trim if the cut landed on a dash
return slug || "fork";
}
/**
* Mirror the backend `validate_fork_workspace_id` so an invalid id fails fast
* — before `existsWorkspace`, datatable cloning (which creates real per-fork
* Postgres databases), and branch creation, none of which get cleaned up on a
* late backend rejection. `id` is the full `wm-fork-<slug>` workspace id.
*/
function validateForkWorkspaceId(id: string): void {
const reject = (reason: string): never => {
throw new Error(
`Fork workspace id \`${id}\` is invalid: ${reason}. Choose a shorter or simpler name/id.`,
);
};
if (id.length > 50) {
reject(`too long (${id.length} chars; max 50 including the \`${WM_FORK_PREFIX}-\` prefix)`);
}
if (id.endsWith(".")) reject("cannot end with '.'");
if (id.endsWith(".lock")) reject("cannot end with '.lock'");
if (id.includes("..")) reject("cannot contain '..'");
if (id.includes("@{")) reject("cannot contain '@{'");
if (id.includes("//")) reject("cannot contain '//'");
for (const ch of id) {
if (":~^?*[\\ ".includes(ch)) reject(`contains forbidden character '${ch}'`);
const code = ch.charCodeAt(0);
if (code < 0x20 || code === 0x7f) reject("contains a control character");
}
for (const component of id.split("/")) {
if (component.startsWith(".")) reject("a path component cannot start with '.'");View on GitHub (pinned to e474e8803c)
Solutions
- Choose a shorter fork workspace name so `wm-fork-<name>` stays ≤ 50 chars
- Use only lowercase alphanumeric and dash characters in the name
- Re-run `wmill workspace fork` with the simplified id
Example fix
// before wmill workspace fork --name my-extremely-long-experimental-feature-branch-name-2026 // after wmill workspace fork --name exp-feature
Defensive patterns
Strategy: validation
Validate before calling
const id = `${WM_FORK_PREFIX}-${slug(name)}`;
if (id.length > 50 || !/^[a-z0-9-]+$/.test(id)) {
throw new Error(`fork id ${id} invalid; shorten or simplify`);
} Type guard
function isValidForkId(id: string): boolean {
return id.length <= 50 && /^wm-fork-[a-z0-9-]+$/.test(id);
} Try / catch
try {
validateForkWorkspaceId(id);
} catch (e) {
log.error(e.message); // includes the specific reason (too long, bad chars)
} Prevention
- Keep fork names short (well under 50 chars including the wm-fork- prefix)
- Use lowercase alphanumeric names with dashes
- Validate the generated id before invoking fork creation to avoid half-created state
When it happens
Trigger: The workspace name given to `wmill workspace fork` produces an id longer than 50 characters or containing characters outside the allowed slug set; `reject` is called with the specific reason.
Common situations: Long descriptive fork names like `wm-fork-my-very-long-experimental-feature-branch-2026` exceeding the limit; names with spaces or uppercase letters.
Related errors
- Invalid migration name '${name}': use only letters, digits,
- Fork workspace name is too long (${effectiveName.length} cha
- Unknown workspace dependencies file format: ${path}. Valid f
- Cannot push flow ${remotePath}: step(s) reference non-worksp
- Completed jobs file must contain an array of jobs
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/d94d319659cf2943.
Report an issue: GitHub.