windmill-labs/windmill · error
Workspace already has datatable(s): ${existing.map((d) => d.
Error message
Workspace already has datatable(s): ${existing.map((d) => d.name).join(", ")}. Re-run with --force to add '${dtName}' (note: fork metadata on existing datatables is not preserved) What it means
`wmill datatable create` also refuses to touch a workspace that already has ANY datatables unless `--force` is passed, because the create path rewrites the workspace datatable config wholesale and fork metadata on existing datatables cannot be read back through the API. This guards against silently losing per-datatable settings when adding a datatable to a non-empty workspace.
Source
Thrown at cli/src/commands/datatable/datatable.ts:132
async function create(
opts: GlobalOptions & { resource?: string; force?: boolean },
name?: string,
) {
const workspace = await resolveWorkspace(opts);
await requireLogin(opts);
const dtName = name ?? DEFAULT_DATATABLE_NAME;
const existing = await wmill.listDataTables({
workspace: workspace.workspaceId,
});
if (existing.some((d) => d.name === dtName)) {
throw new Error(`Datatable '${dtName}' already exists in this workspace`);
}
// edit_datatable_config replaces the whole settings object, and fork
// metadata on existing datatables can't be read back through the API —
// so only touch a non-empty config when explicitly asked to.
if (existing.length > 0 && !opts.force) {
throw new Error(
`Workspace already has datatable(s): ${existing
.map((d) => d.name)
.join(", ")}. Re-run with --force to add '${dtName}' ` +
"(note: fork metadata on existing datatables is not preserved)",
);
}
const datatables: Record<
string,
{ database: { resource_type: "postgresql" | "instance"; resource_path?: string } }
> = {};
for (const d of existing) {
datatables[d.name] = {
database: {
resource_type: d.resource_type as "postgresql" | "instance",
resource_path: d.resource_path ?? undefined,
},
};View on GitHub (pinned to e474e8803c)
Solutions
- Re-run with `--force`: `wmill datatable create <name> --force` (accepting that fork metadata on existing datatables is not preserved).
- Create the datatable in a fresh/empty workspace if preserving metadata matters.
- Recreate the fork metadata manually after a forced create, if unavoidable.
Example fix
// before wmill datatable create analytics // after wmill datatable create analytics --force
Defensive patterns
Strategy: validation
Validate before calling
const existing = await wmill.listDataTables({ workspace });
if (existing.length > 0 && !process.env.FORCE_DT) throw new Error('workspace not empty; pass --force intentionally'); Type guard
null
Try / catch
try { await create() } catch (e) { if (String(e).includes('Re-run with --force')) promptUserForForce(); else throw e; } Prevention
- Read the error fully — it lists existing datatables and the exact flag needed
- Understand that --force drops fork metadata before using it
- Create additional datatables in dedicated workspaces when metadata preservation matters
When it happens
Trigger: Running `wmill datatable create <name>` in a workspace where `listDataTables` returns at least one datatable (and the requested name itself doesn't collide) without the `--force` flag.
Common situations: Adding a second datatable to a shared workspace that was set up by `wmill datatable init`-style tooling; workspaces whose datatables carry fork metadata that a blind config rewrite would destroy.
Related errors
- Datatable '${dtName}' already exists in this workspace
- You can only delete forked workspaces where the workspace id
- Could not fetch datatable schemas: ${errorMessage}
- Failed to run new datatable migrations: ${e?.body ?? e?.mess
- 0A000
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/91c11d79c61e5ead.
Report an issue: GitHub.