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
- Rename the file to the required `<datatable>/<timestamp>_<name>` layout, e.g. `my_table/1726012345_create_users`
- Ensure the timestamp segment is present and followed by `_`
- Regenerate the migration with the CLI so the filename follows the convention
- 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
- Always scaffold migrations via the CLI rather than creating files by hand
- Keep the `<datatable>/<timestamp>_<name>` filename convention; never rename the timestamp prefix
- Use forward slashes; avoid OS-specific separators in stored paths
- Glob only `*_migration`-style patterns to avoid picking up stray files
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
- Invalid migration name '${name}': use only letters, digits,
- Fork workspace name is too long (${effectiveName.length} cha
- Fork workspace id \`${id}\` is invalid: ${reason}. Choose a
- Invalid AI agent tool name(s): ${invalidToolNames.map((t) =>
- result.substring(__RESULT_ERR_PREFIX.length)
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/21e507e39abd83fd.
Report an issue: GitHub.