windmill-labs/windmill · error · Error
Workspace '${forkWorkspaceId}' is not a fork (no parent_work
Error message
Workspace '${forkWorkspaceId}' is not a fork (no parent_workspace_id). You can only merge from a forked workspace. What it means
The merge flow fetches the user's workspaces from the backend and looks up the resolved fork id. If the workspace exists but has no `parent_workspace_id`, it is not a fork, and merging from it is meaningless, so the command throws. (It also throws earlier if the id isn't found at all.)
Source
Thrown at cli/src/commands/workspace/merge.ts:277
throw new Error("Not logged in. Please run 'wmill workspace add' first.");
}
const remote = workspace.remote;
setClient(
token,
remote.endsWith("/") ? remote.substring(0, remote.length - 1) : remote
);
const forkWorkspaceId = workspace.workspaceId;
// 2. Find parent workspace
const userWorkspaces = await wmill.listUserWorkspaces();
const forkEntry = userWorkspaces.workspaces?.find(
(w) => w.id === forkWorkspaceId
);
if (!forkEntry?.parent_workspace_id) {
throw new Error(
`Workspace '${forkWorkspaceId}' is not a fork (no parent_workspace_id). ` +
`You can only merge from a forked workspace.`
);
}
const parentWorkspaceId = forkEntry.parent_workspace_id;
log.info(
`Fork: ${colors.bold(forkWorkspaceId)} → Parent: ${colors.bold(parentWorkspaceId)}`
);
// 3. Compare workspaces
log.info("Comparing workspaces...");
const comparison = await wmill.compareWorkspaces({
workspace: parentWorkspaceId,
targetWorkspaceId: forkWorkspaceId,
});
if (comparison.skipped_comparison) {View on GitHub (pinned to e474e8803c)
Solutions
- Switch to the fork branch / workspace created via `wmill workspace fork` before merging
- Re-create the fork properly with `wmill workspace fork` so parent_workspace_id is set
- Verify with the workspace list on the backend that the target workspace is a fork
Example fix
// before git checkout main && wmill workspace merge # main is the parent // after git checkout my-fork && wmill workspace merge
Defensive patterns
Strategy: validation
Validate before calling
const { workspaces } = await wmill.listUserWorkspaces();
const fork = workspaces?.find(w => w.id === forkWorkspaceId);
if (!fork?.parent_workspace_id) {
throw new Error(`${forkWorkspaceId} is not a fork; run wmill workspace fork to create one.`);
} Type guard
function isForkEntry(w: { id: string; parent_workspace_id?: string | null }): w is { id: string; parent_workspace_id: string } {
return !!w.parent_workspace_id;
} Try / catch
try {
await mergeWorkspaces(opts);
} catch (e) {
if (e.message.includes('is not a fork')) {
log.error('Create the fork with wmill workspace fork first.');
} else throw e;
} Prevention
- Create forks only via wmill workspace fork so parent_workspace_id is recorded
- Run merge from the fork branch, not the base branch
- Inspect listUserWorkspaces before merging
When it happens
Trigger: `wmill workspace merge` while the resolved workspace id corresponds to a normal (non-fork) workspace on the backend — e.g. merging from a base workspace or an id without a recorded parent.
Common situations: Running merge while on the main/base branch mapped to the parent workspace; fork created out-of-band (workspace created manually, not via `wmill workspace fork`) so no parent link exists; fork relationship removed server-side.
Related errors
- Could not resolve workspace from branch name. Make sure you
- Invalid direction '${opts.direction}'. Use 'to-parent' or 't
- App ${appPath} not found
- Dependency generation failed: ${queueResponse.status} ${queu
- Failed to poll dependencies job ${jobId}: ${e?.message ?? e}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/babd44685127dc4c.
Report an issue: GitHub.