{"record":{"id":"55a093ee4ddcc0ef","repo":"windmill-labs/windmill","slug":"datatable-dtname-already-exists-in-this-works","errorCode":null,"errorMessage":"Datatable '${dtName}' already exists in this workspace","messagePattern":"Datatable '(.+?)' already exists in this workspace","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/src/commands/datatable/datatable.ts","lineNumber":126,"sourceCode":"  .option(\n    \"-d --datatable <datatable:string>\",\n    \"Target datatable (default: main)\",\n  )\n  .action(migrateDown as any);\n\nasync function create(\n  opts: GlobalOptions & { resource?: string; force?: boolean },\n  name?: string,\n) {\n  const workspace = await resolveWorkspace(opts);\n  await requireLogin(opts);\n  const dtName = name ?? DEFAULT_DATATABLE_NAME;\n\n  const existing = await wmill.listDataTables({\n    workspace: workspace.workspaceId,\n  });\n  if (existing.some((d) => d.name === dtName)) {\n    throw new Error(`Datatable '${dtName}' already exists in this workspace`);\n  }\n  // edit_datatable_config replaces the whole settings object, and fork\n  // metadata on existing datatables can't be read back through the API —\n  // so only touch a non-empty config when explicitly asked to.\n  if (existing.length > 0 && !opts.force) {\n    throw new Error(\n      `Workspace already has datatable(s): ${existing\n        .map((d) => d.name)\n        .join(\", \")}. Re-run with --force to add '${dtName}' ` +\n        \"(note: fork metadata on existing datatables is not preserved)\",\n    );\n  }\n\n  const datatables: Record<\n    string,\n    { database: { resource_type: \"postgresql\" | \"instance\"; resource_path?: string } }\n  > = {};\n  for (const d of existing) {","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/cli/src/commands/datatable/datatable.ts#L108-L144","documentation":"`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').","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait $`wmill datatable create main`;\n// after\nawait $`wmill datatable list || wmill datatable create main`;","handlingStrategy":"validation","validationCode":"const existing = await wmill.listDataTables({ workspace });\nif (existing.some(d => d.name === name)) console.log('datatable exists, skipping create');","typeGuard":"null","tryCatchPattern":"try { await wmill.datatableCreate(name) } catch (e) { if (String(e).includes('already exists')) return; throw e; }","preventionTips":["Check existence with list before create in idempotent scripts","Use unique, per-environment datatable names","Make setup scripts skip-on-exists rather than fail"],"tags":["cli","datatable","duplicate","idempotency"],"backgroundTag":"resource-already-exists","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"}