windmill-labs/windmill · error
Datatable '${dtName}' already exists in this workspace
Error message
Datatable '${dtName}' already exists in this workspace What it means
`wmill datatable create` refuses to create a datatable whose name already exists in the target workspace. Before creating, it lists existing datatables via `wmill.listDataTables` and throws if one matches the requested name (default 'main').
Source
Thrown at cli/src/commands/datatable/datatable.ts:126
.option(
"-d --datatable <datatable:string>",
"Target datatable (default: main)",
)
.action(migrateDown as any);
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) {View on GitHub (pinned to e474e8803c)
Solutions
- Run `wmill datatable list` to confirm the datatable exists; if it's the one you want, skip creation.
- Use a different name for the new datatable.
- If you intended to recreate/replace, delete the existing datatable first, then create.
Example fix
// before await $`wmill datatable create main`; // after await $`wmill datatable list || wmill datatable create main`;
Defensive patterns
Strategy: validation
Validate before calling
const existing = await wmill.listDataTables({ workspace });
if (existing.some(d => d.name === name)) console.log('datatable exists, skipping create'); Type guard
null
Try / catch
try { await wmill.datatableCreate(name) } catch (e) { if (String(e).includes('already exists')) return; throw e; } Prevention
- Check existence with list before create in idempotent scripts
- Use unique, per-environment datatable names
- Make setup scripts skip-on-exists rather than fail
When it happens
Trigger: Running `wmill datatable create` (with or without an explicit name) when `listDataTables` already returns a datatable with that name — most commonly re-running the create command twice, or creating the default 'main' datatable in a workspace that already has it.
Common situations: Idempotent setup scripts run twice; onboarding docs that tell users to create 'main' while the workspace was provisioned with it already; switching workspaces accidentally and re-creating.
Related errors
- Workspace already has datatable(s): ${existing.map((d) => d.
- File already exists: ${filePath}
- 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/55a093ee4ddcc0ef.
Report an issue: GitHub.