windmill-labs/windmill · error

Invalid datatable migration path: ${path}

Error message

Invalid datatable migration path: ${path}

What it means

parseDatatableMigrationDeployPath expects a datatable migration path shaped `<datatable>/<timestamp>_<name>` (e.g. `my_table/1726012345_create_users`). It throws when the path contains no `/` separating the datatable from the rest, or no `_` after the slash separating the timestamp from the migration name. This is a strict structural validation before the parts are sliced out.

Source

Thrown at cli/windmill-utils-internal/src/deploy.ts:331

  ];
}

function toError(e: unknown): string {
  const err = e as { body?: string; message?: string };
  return err.body || err.message || String(e);
}

// A datatable-migration diff item's path is `<datatable>/<timestamp>_<name>`
// (mirrors the backend, e.g. `mydt/20260101000001_create_users`).
export function parseDatatableMigrationDeployPath(path: string): {
  datatable: string;
  timestamp: number;
  name: string;
} {
  const slash = path.indexOf("/");
  const underscore = slash >= 0 ? path.indexOf("_", slash + 1) : -1;
  if (slash < 0 || underscore < 0) {
    throw new Error(`Invalid datatable migration path: ${path}`);
  }
  const datatable = path.slice(0, slash);
  const timestamp = Number(path.slice(slash + 1, underscore));
  const name = path.slice(underscore + 1);
  if (!datatable || !Number.isFinite(timestamp) || !name) {
    throw new Error(`Invalid datatable migration path: ${path}`);
  }
  return { datatable, timestamp, name };
}

// The backend rejects `upsertDatatableMigration` when the target data table
// hasn't opted in to migrations. Turn that opaque 400 into an explicit,
// deploy-context message (falls back to the original error otherwise).
function asMigrationsDisabledError(e: unknown, datatable: string): unknown {
  const msg = (e as { body?: string; message?: string })?.body ?? ''
  if (typeof msg === "string" && /migrations are not enabled/i.test(msg)) {
    return new Error(
      `Data table '${datatable}' has not opted in to migrations on the target workspace; enable migrations for it there before deploying its migrations.`

View on GitHub (pinned to e474e8803c)

Solutions

  1. Rename the file to the required `<datatable>/<timestamp>_<name>` layout, e.g. `my_table/1726012345_create_users`
  2. Ensure the timestamp segment is present and followed by `_`
  3. Regenerate the migration with the CLI so the filename follows the convention
  4. Check for backslash separators on Windows and use forward slashes

Example fix

// before
parseDatatableMigrationDeployPath("1726012345_create_users")   // no datatable/
parseDatatableMigrationDeployPath("my_table/create_users")    // no timestamp_

// after
parseDatatableMigrationDeployPath("my_table/1726012345_create_users")
Defensive patterns

Strategy: validation

Validate before calling

function isValidMigrationPath(path: string): boolean {
  const m = /^([^/]+)\/(\d+)_([^/]+)$/.exec(path);
  return m !== null && m[1] !== '' && m[3] !== '';
}
if (!isValidMigrationPath(p)) throw new Error(`Bad migration path: ${p}`);

Type guard

function isMigrationPath(p: string): p is `${string}/${number}_${string}` {
  return /^[^/]+\/\d+_[^/]+$/.test(p);
}

Try / catch

try {
  const { datatable, timestamp, name } = parseDatatableMigrationDeployPath(p);
} catch (e) {
  console.error(`${p} must look like <datatable>/<timestamp>_<name>`);
  process.exit(1);
}

Prevention

When it happens

Trigger: Calling parseDatatableMigrationDeployPath (via mergeWorkspaces or the `{datatable, timestamp}` caller) with a path missing `/` (bare filename like `1726012345_create_users`) or missing the `_` timestamp separator (like `my_table/1726012345create_users`).

Common situations: Hand-constructing migration file paths instead of using the CLI's scaffolding; renaming migration files and dropping the `timestamp_` prefix; a glob/scan picking up non-migration files inside the datatable directory; OS-specific path separators (`\` on Windows).

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/21e507e39abd83fd. Report an issue: GitHub.