Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/reference/error-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,7 @@ Runner-level failure during apply (`db init`, `db update`, `migrate`): the plan'

### MIGRATION.DESTRUCTIVE_CHANGES

The planned operations include destructive changes (e.g. DROP) and the command was run without explicit consent. `db update` asks for that consent instead of failing: interactively it asks you to type the name of the database it is about to change, and outside an interactive terminal it is granted by `--confirm <database>` (`--yes` accepts declared prompt defaults and never grants consent; `--confirm` is read only when the run is non-interactive or `--yes` is set, so a script run from a terminal needs `--no-interactive --confirm <database>`). The name is the `database` a driver connection object carries, or the connection URL's first path segment, else its host, falling back to the target id. A run with nobody to ask and no `--confirm` settles as `CLI.CONSENT_REQUIRED` at exit 2; a run whose prompt is cancelled settles as `CLI.PROMPT_CANCELLED` at exit 3. `--dry-run` never asks — it settles as this error instead. Use it to preview the operations first.
The planned operations include destructive changes (e.g. DROP) and the command was run without explicit consent. `db update` asks for that consent instead of failing: interactively it asks you to type the name of the database it is about to change, and outside an interactive terminal it is granted by `--confirm <database>` (`--yes` accepts declared prompt defaults and never grants consent; `--confirm` is read only when the run is non-interactive or `--yes` is set, so a script run from a terminal needs `--no-interactive --confirm <database>`). The name is the `database` a driver connection object carries, or the connection URL's first path segment, else its host, falling back to the target id. A run with nobody to ask and no `--confirm` settles as `CLI.CONSENT_REQUIRED` at exit 2; a run whose prompt is cancelled settles as `CLI.PROMPT_CANCELLED` at exit 3. `--dry-run` never asks — it settles as this error instead. Use it to preview the operations first. `migration plan` raises the same refusal before writing an auto-baseline package (planned on an empty migrations directory from the `db` ref) whose operations would remove data when applied; there the consent token is the project directory name, so a non-interactive run passes `--no-interactive --confirm <directory>`, and a consented re-run that no longer plans the consented baseline settles as `MIGRATION.CONSENT_PLAN_MISMATCH`. Meta at the `migration plan` site: `destructiveOperations`, `planHash`.

### MIGRATION.DIR_EXISTS

Expand Down Expand Up @@ -943,7 +943,7 @@ A migration package on disk is corrupt: the `migrationHash` stored in `migration

### MIGRATION.HASH_NOT_IN_GRAPH

A contract hash the user supplied (or that a ref resolved to) is not a node in the on-disk migration graph — raised during plan resolution (`migration plan --from`), `ref set`, and `migration new --from`. The envelope lists the reachable hashes and suggests a valid one or running `migration plan` to introduce it. Meta: `hash`/`resolvedHash`, `reachableHashes` or `reachableRefs`, sometimes `graphTipHash`; none at the `migration new` site.
A contract hash the user supplied (or that a ref resolved to) is not a node in the on-disk migration graph — raised during plan resolution (`migration plan --from`), `ref set`, and `migration new --from` (including `--from` on an empty migrations directory, where there is no migration target it could name). The envelope lists the reachable hashes and suggests a valid one or running `migration plan` to introduce it. Meta: `hash`/`resolvedHash`, `reachableHashes` or `reachableRefs`, sometimes `graphTipHash`; none at the `migration new` sites.

### MIGRATION.INVALID_DEFAULT_EXPORT

Expand Down Expand Up @@ -1083,7 +1083,7 @@ The `providedInvariants` stored in `migration.json` disagrees with the canonical

### MIGRATION.REF_AMBIGUOUS

A contract or migration reference prefix matches more than one candidate (raised by the shared ref-resolution mapper used across CLI commands). Provide a longer prefix or the full hash. Meta: `input`, `candidates`, `grammar`.
A contract or migration reference prefix matches more than one candidate (raised by the shared ref-resolution mapper used across CLI commands, and by `migration new --from` when the prefix matches several migration target hashes). Provide a longer prefix or the full hash. Meta: `input`, `candidates`, and at the shared-mapper site `grammar`.

### MIGRATION.REF_INVALID_FORMAT

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,23 +127,44 @@ export async function executeMigrationNewCommand(

let fromHash: string | null = null;

if (packages.length > 0) {
if (options.from) {
const match = packages.find((p) => p.metadata.to.startsWith(options.from!));
if (!match) {
return notOk(
errorRuntime('MIGRATION.HASH_NOT_IN_GRAPH', 'Starting contract not found', {
why: `No migration with to hash matching "${options.from}" exists in ${appMigrationsRelative}`,
fix: 'Check that the --from hash matches a known migration target hash.',
}),
);
}
fromHash = match.metadata.to;
} else {
const latestMigration = findLatestMigration(graph);
if (latestMigration) {
fromHash = latestMigration.to;
}
if (options.from !== undefined) {
if (packages.length === 0) {
return notOk(
errorRuntime('MIGRATION.HASH_NOT_IN_GRAPH', '--from has no meaning on an empty graph', {
why: `--from "${options.from}" was passed, but ${appMigrationsRelative} contains no migrations, so there is no migration target hash it could name.`,
fix: 'Omit --from to scaffold the first migration (it records a baseline origin). `migration new --from` accepts the full 64-hex target hash of an existing migration, or a unique prefix of one.',
}),
);
}
const matchedHashes = [
...new Set(
packages
.filter((p) => p.metadata.to.startsWith(options.from ?? ''))
.map((p) => p.metadata.to),
),
].sort();
if (matchedHashes.length === 0) {
return notOk(
errorRuntime('MIGRATION.HASH_NOT_IN_GRAPH', 'Starting contract not found', {
why: `No migration with to hash matching "${options.from}" exists in ${appMigrationsRelative}`,
fix: 'Check that the --from hash matches a known migration target hash. `migration new --from` accepts the full 64-hex target hash of an existing migration, or a unique prefix of one.',
}),
);
}
if (matchedHashes.length > 1) {
return notOk(
errorRuntime('MIGRATION.REF_AMBIGUOUS', `Ambiguous --from prefix: "${options.from}"`, {
why: `"${options.from}" is a prefix of ${matchedHashes.length} migration target hashes in ${appMigrationsRelative}: ${matchedHashes.join(', ')}`,
fix: 'Provide a longer prefix or the full 64-hex target hash to disambiguate.',
meta: { input: options.from, candidates: matchedHashes },
}),
);
}
fromHash = matchedHashes[0] ?? null;
} else if (packages.length > 0) {
const latestMigration = findLatestMigration(graph);
if (latestMigration) {
fromHash = latestMigration.to;
}
}

Expand Down
Loading
Loading