diff --git a/.github/workflows/error-reference-check.yml b/.github/workflows/error-reference-check.yml index e98ee234f6..907251c453 100644 --- a/.github/workflows/error-reference-check.yml +++ b/.github/workflows/error-reference-check.yml @@ -1,9 +1,10 @@ name: Error Reference Check -# The published error-reference page must list every structured error code the -# product (prisma/prisma main) can emit — each emitted error links to -# /docs/orm/reference/error-reference#. This check fails if any -# known code is missing from the page, even if the sync workflow breaks. +# The published error-reference pages must list every structured error code +# the products can emit — prisma/prisma (main) errors link to +# /docs/orm/reference/error-reference#, prisma/prisma-cli (main) errors +# to /docs/cli/error-reference#. This check fails if any known code is +# missing from its page, even if the sync workflow breaks. # # Runs on pushes to main, on PRs that touch the page or its tooling, and on a # daily schedule so drift introduced upstream is flagged without blocking @@ -15,6 +16,7 @@ on: pull_request: paths: - apps/docs/content/docs/orm/reference/error-reference.mdx + - apps/docs/content/docs/cli/error-reference.mdx - apps/docs/scripts/generate-error-reference.mjs - .github/workflows/error-reference-check.yml - .github/workflows/sync-error-reference-docs.yml @@ -43,10 +45,21 @@ jobs: path: prisma-src persist-credentials: false + - name: Checkout prisma/prisma-cli (main) + uses: actions/checkout@v4 + with: + repository: prisma/prisma-cli + ref: main + path: prisma-cli-src + persist-credentials: false + - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: "20" - - name: Verify page lists every known error code + - name: Verify ORM page lists every known error code run: node prisma-src/scripts/list-error-codes.mjs --root prisma-src --verify apps/docs/content/docs/orm/reference/error-reference.mdx + + - name: Verify CLI page lists every known error code + run: node prisma-cli-src/scripts/list-error-codes.mjs --root prisma-cli-src --verify apps/docs/content/docs/cli/error-reference.mdx diff --git a/.github/workflows/sync-error-reference-docs.yml b/.github/workflows/sync-error-reference-docs.yml index 3a83169cfa..b8f431c59f 100644 --- a/.github/workflows/sync-error-reference-docs.yml +++ b/.github/workflows/sync-error-reference-docs.yml @@ -32,28 +32,44 @@ jobs: path: prisma-src persist-credentials: false + - name: Checkout prisma/prisma-cli (main) + uses: actions/checkout@v4 + with: + repository: prisma/prisma-cli + ref: main + path: prisma-cli-src + persist-credentials: false + - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: "20" - - name: Generate error reference page + - name: Generate ORM error reference page working-directory: apps/docs - run: node ./scripts/generate-error-reference.mjs --source ../../prisma-src/docs/reference/error-reference.md + run: node ./scripts/generate-error-reference.mjs --target orm --source ../../prisma-src/docs/reference/error-reference.md - - name: Verify page lists every known error code + - name: Verify ORM page lists every known error code run: node prisma-src/scripts/list-error-codes.mjs --root prisma-src --verify apps/docs/content/docs/orm/reference/error-reference.mdx + - name: Generate CLI error reference page + working-directory: apps/docs + run: node ./scripts/generate-error-reference.mjs --target cli --source ../../prisma-cli-src/docs/reference/error-reference.md + + - name: Verify CLI page lists every known error code + run: node prisma-cli-src/scripts/list-error-codes.mjs --root prisma-cli-src --verify apps/docs/content/docs/cli/error-reference.mdx + - name: Check for changes id: changes run: | - if [[ -z "$(git status --porcelain --untracked-files=all -- apps/docs/content/docs/orm/reference/error-reference.mdx)" ]]; then - echo "changed=false" >> $GITHUB_OUTPUT + PAGES=(apps/docs/content/docs/orm/reference/error-reference.mdx apps/docs/content/docs/cli/error-reference.mdx) + if [[ -z "$(git status --porcelain --untracked-files=all -- "${PAGES[@]}")" ]]; then + echo "changed=false" >> "$GITHUB_OUTPUT" echo "No changes detected" else - echo "changed=true" >> $GITHUB_OUTPUT + echo "changed=true" >> "$GITHUB_OUTPUT" echo "Changes detected:" - git status --short -- apps/docs/content/docs/orm/reference/error-reference.mdx + git status --short -- "${PAGES[@]}" fi - name: Commit and push @@ -65,7 +81,7 @@ jobs: run: | git config user.email "prismabots@gmail.com" git config user.name "Prismo" - git add apps/docs/content/docs/orm/reference/error-reference.mdx + git add apps/docs/content/docs/orm/reference/error-reference.mdx apps/docs/content/docs/cli/error-reference.mdx git commit -m "chore(docs): sync Prisma 8 error reference" git push "https://x-access-token:${BOT_TOKEN}@github.com/${TARGET_REPO}.git" "HEAD:${TARGET_REF}" diff --git a/apps/docs/content/docs/cli/error-reference.mdx b/apps/docs/content/docs/cli/error-reference.mdx new file mode 100644 index 0000000000..1df1a0dddd --- /dev/null +++ b/apps/docs/content/docs/cli/error-reference.mdx @@ -0,0 +1,561 @@ +--- +title: Error reference +description: Every structured error code the unified Prisma CLI can emit, by namespace, with the condition that raises it. +url: /cli/error-reference +metaTitle: Error reference | Prisma 8 CLI +metaDescription: Every structured error code the unified Prisma CLI can emit, by namespace, with the condition that raises it. +--- + +{/* Generated by scripts/generate-error-reference.mjs from + https://github.com/prisma/prisma-cli/blob/main/docs/reference/error-reference.md + Do not edit by hand — changes are overwritten by the sync workflow. */} + +Every user-facing error the unified Prisma CLI emits is a structured envelope identified by a dotted `NAMESPACE.SUBCODE` code (see [Error Conventions](https://github.com/prisma/prisma-cli/blob/main/docs/product/error-conventions.md) and [ADR 0003](https://github.com/prisma/prisma-cli/blob/main/docs/architecture/adrs/0003-structured-output-and-errors.md)). This page lists every published code. Each code anchors as `#` — the fragment an emitted error's `docsUrl` resolves to. This page is generated from the canonical registry in the `prisma/prisma-cli` repository, whose CI requires every code in production source to be documented before it ships. + +Recognize an error programmatically by running with `--json` and matching on `error.code` in the emitted envelope — never on message text. Envelopes carry `message`, and optionally `why`, `fix`, `where`, `meta`, `cause`, `nextActions`, and `docsUrl`. + +Most codes on this page are expected failures. Some are warn-severity diagnostics that ride a successful run: the command completes and exits `0`, and the diagnostic carries the code (the entry says so where it applies). The process exit-code contract is in [Error Conventions](https://github.com/prisma/prisma-cli/blob/main/docs/product/error-conventions.md). + +Every code on this page is assigned where the error is raised, and this page lists every code the CLI can emit. No boundary invents a code from a server response or rewrites one on the way out, so an error's code never depends on which command you reached the failure through. When a REST API request fails, the CLI raises the domain's registered `*.API_ERROR` code and carries the API's own code and HTTP status in `meta.apiCode` and `meta.status`, where they are data you can read rather than a code you have to guess at. + +Namespaces: + +| Namespace | Covers | +| --- | --- | +| `AUTH` | Workspace authentication and sessions (`prisma auth`, credential resolution) | +| `BRANCH` | Branch listing (`prisma branch`) | +| `BUCKET` | Bucket and bucket-key management (`prisma bucket`) | +| `CLI` | Engine-level invocation: arguments, config loading, prompts, consent, credentials, child processes | +| `FEEDBACK` | Sending product feedback (`prisma feedback`) | +| `GIT` | Git repository connections (`prisma git`) | +| `INIT` | Project initialization diagnostics (`prisma init`) | +| `POSTGRES` | Database management (`prisma postgres`) | +| `PROJECT` | Project and environment management (`prisma project`) | +| `SERVICE` | Deployed service management (`prisma service`) | +| `SKILLS` | Agent-skill delivery (`prisma skills`) | + +## AUTH + +### AUTH.CREDENTIAL_WORKSPACE_MISMATCH [#AUTH.CREDENTIAL_WORKSPACE_MISMATCH] + +A credential's `workspace_id` claim disagrees with the workspace it is being stored under — raised by every CredentialManager (the CLI's file-backed manager and the engine's in-memory one) both when `createSession` receives a token claiming a different workspace and when a rotated token written back during refresh would re-scope an existing session. The fix is to run `prisma auth login` again and pick the intended workspace. Meta: none. + +### AUTH.LOGIN_WORKSPACE_UNKNOWN [#AUTH.LOGIN_WORKSPACE_UNKNOWN] + +`prisma auth login` completed the browser sign-in but the minted credential carries no `workspace_id` claim, so no workspace session can be keyed by it. The fix is to sign in again and pick a workspace in the browser. Meta: none. + +### AUTH.NO_SESSION_FOR_WORKSPACE [#AUTH.NO_SESSION_FOR_WORKSPACE] + +A workspace reference matched none of the stored workspace sessions — raised by the command-side ref resolver behind `prisma auth workspace use` and `prisma auth workspace logout` (exact id match first, then case-insensitive name match), and by the credential managers when a session operation names a workspace with no stored record. Sessions are created only by `prisma auth login`, so the suggested fix is to sign in and pick that workspace in the browser; the workspace reference appears in the message, not in meta. Meta: none. + +### AUTH.NO_WORKSPACE_SESSIONS [#AUTH.NO_WORKSPACE_SESSIONS] + +`prisma auth workspace use` was run with zero stored workspace sessions, so there is nothing to select among — the command only selects, it never creates a session or opens a browser. The fix is to run `prisma auth login` first. Meta: none. + +### AUTH.SERVICE_TOKEN_EMPTY [#AUTH.SERVICE_TOKEN_EMPTY] + +The `PRISMA_SERVICE_TOKEN` environment variable is set but blank; a blank token authenticates nothing while still overriding stored workspace sessions, so the CLI surfaces it instead of silently ignoring it. It is raised identically wherever the environment credential is read — `activeCredential()`, the command needs check, and the engine's request path, including at the start of `prisma auth login` before a browser opens. The suggested actions are to unset the variable or set it to a valid service token. Meta: none. + +### AUTH.SERVICE_TOKEN_REJECTED [#AUTH.SERVICE_TOKEN_REJECTED] + +The management API rejected (401) the service token supplied through `PRISMA_SERVICE_TOKEN`; such a token carries no refresh token and can never be renewed, and nothing stored is cleared. Built only through the shared `credentialRejectedError` dispatcher in the engine's API request path — the one place wording differs by credential origin (a stored session with the same failure gets `CLI.CREDENTIALS_REQUIRED` instead). The suggested action is to replace the variable with a valid service token or unset it to fall back to stored sessions. Meta: none. + +### AUTH.SESSIONS_UNSUPPORTED [#AUTH.SESSIONS_UNSUPPORTED] + +A session mutation (`createSession`, `selectSession`, `endSession`, `endAllSessions`) was attempted on a host that uses the environment-only credential manager, whose sole credential source is `PRISMA_SERVICE_TOKEN` (plus `PRISMA_WORKSPACE_ID`) — such hosts, like composer's rebuilt CLI, hold no stored sessions, so there is nothing to create, select, or end. The suggested action is to set or change the environment variable instead. Meta: none. + +### AUTH.USAGE_ERROR [#AUTH.USAGE_ERROR] + +A command that needs an active workspace found an authenticated credential that names no workspace — raised by the resource commands' `resolveActiveWorkspace` and the service commands' `requireWorkspace`, which read the engine's pinned credential; an environment token whose claims carry no workspace id is the usual cause. The suggested fix is to run `prisma auth login` and choose a workspace. Meta: none. + +### AUTH.WORKSPACE_AMBIGUOUS [#AUTH.WORKSPACE_AMBIGUOUS] + +A user-typed workspace name matched more than one workspace, from two raise sites with different meta: the session-ref resolver behind `prisma auth workspace use`/`logout` when several stored sessions share the name (meta carries `workspaceIds`), and `prisma project transfer` when a `--to-workspace` reference matches several authenticated workspaces (meta carries `workspaceRef` and `matches`, each match holding `id`, `name`, `credentialWorkspaceId`). Both point the user at `prisma auth workspace list` to retry with an exact workspace id. Meta: `workspaceIds` (workspace commands) or `workspaceRef`, `matches` (project transfer). + +### AUTH.WORKSPACE_NOT_AUTHENTICATED [#AUTH.WORKSPACE_NOT_AUTHENTICATED] + +`prisma project transfer` could not resolve the transfer recipient: the `--to-workspace` reference matched no stored OAuth session, or the matched recipient session proved invalid. The suggested fix is to run `prisma auth login` and authorize that workspace, after checking `prisma auth workspace list`. Meta: `workspaceRef`. + +## BRANCH + +### BRANCH.API_ERROR [#BRANCH.API_ERROR] + +A REST API call made by `prisma branch list` failed. The `why` carries the API's message or, failing that, the HTTP status, and the fix suggests rerunning with `--log-level verbose` for the response details. Meta: `status`, `apiCode` (the API's own error code, when the response supplied one). + +## BUCKET + +### BUCKET.API_ERROR [#BUCKET.API_ERROR] + +A bucket REST API request (listing, creating, or deleting buckets or bucket keys) failed — raised by the provider (`lib/bucket/provider.ts`). The `why` carries the API's message or HTTP status, and the fix is the API's hint when it sent one. An HTTP 401 or 403 raises this code too, with a `why` saying the API rejected the request as unauthorized and a `prisma auth login` next action. Meta: `status`, `apiCode` (the API's own error code, when the response supplied one). + +### BUCKET.KEY_SECRET_MISSING [#BUCKET.KEY_SECRET_MISSING] + +`prisma bucket key create` created the key, but the REST API response omitted part of the one-time credential payload (secret access key, access key id, endpoint, or bucket name), so the CLI cannot show credentials it will never see again. The fix is to create another key and store the returned credentials immediately. Meta: none. + +### BUCKET.USAGE_ERROR [#BUCKET.USAGE_ERROR] + +A bucket subcommand was called without its required id argument: `bucket delete` and `bucket key create`/`bucket key list` need a bucket id, and `bucket key delete` needs both a bucket id and a key id. The nextActions point at `bucket list` (or `bucket key list`) to find the ids. Meta: none. + +## CLI + +### CLI.ABORTED [#CLI.ABORTED] + +The run's abort signal fired before the command completed — a thrown abort error is recognized in settlement and reported as this code rather than as a bug. When the abort came from a delivered SIGINT/SIGTERM the run exits 130/143; an abort with no recorded signal (an engine-internal abort) exits 3. Meta: none. + +### CLI.AUTH_SERVICE_ERROR [#CLI.AUTH_SERVICE_ERROR] + +The authentication service failed transiently while refreshing a stored OAuth session; the stored credentials are left untouched, and the guidance is to retry rather than sign in again, because the credentials themselves were not rejected. Meta: none. + +### CLI.BROWSER_WAIT_TIMEOUT [#CLI.BROWSER_WAIT_TIMEOUT] + +A `ctx.prompt.browserWait` flow (the command opened a URL and polled for the user to finish there) reached its timeout before the poll succeeded. `prisma git connect` catches this code from its GitHub-app install wait and rethrows a command-specific error, so consumers usually see it from other browserWait flows. Meta: `url`, `timeoutMs`. + +### CLI.CHILD_PROCESS_FAILED [#CLI.CHILD_PROCESS_FAILED] + +Emitted only as a json-mode error envelope when a command that handed the terminal to a child process (`exitWithChildStatus`) saw that child exit non-zero or die on a signal; the run's exit code is the child's own status verbatim, not the CLI's usual 2. Meta: `exitCode`, `signal`. + +### CLI.COMMAND_MOVED [#CLI.COMMAND_MOVED] + +The user typed a retired command path, or a retired flag on a surviving command, that the redirect table claims; instead of failing as unknown, the run names the replacement invocation as a run-command next action, with the retirement reason in `why` when one is recorded. Exits 2. Meta: none. + +### CLI.CONFIG_MISSING_MARKER [#CLI.CONFIG_MISSING_MARKER] + +The evaluated `prisma.config.ts` default export carries no `$prismaConfig` version marker — most likely a Prisma 7 config, which uses the same filename — so the loader stops rather than misread it; the fix is to wrap the exported object in `definePrismaConfig`. Raised by the config loader for any command with a `needs.config` section. The file's absolute path is in `where.path`. Meta: none. + +### CLI.CONFIG_NOT_FOUND [#CLI.CONFIG_NOT_FOUND] + +The file `--config` named does not exist. Only an explicitly named file is an error — an absent `prisma.config.ts` found by discovery is fine, because section validators own absence and supply defaults. The path is in `where.path`. Meta: none. + +### CLI.CONFIG_SECTION_INVALID [#CLI.CONFIG_SECTION_INVALID] + +The config section a command declared in `needs.config` failed its validator; the individual problems travel as accompanying diagnostics on the envelope, and the summary names the section and the config file actually read (respecting `--config`). Raised by the engine's needs check before the handler runs. Meta: none. + +### CLI.CONFIG_UNKNOWN_SECTION [#CLI.CONFIG_UNKNOWN_SECTION] + +The config file has a top-level key that is not a section any mounted command or command family declares; the set of section names is closed, so an unrecognized key is a typo or leftover the CLI refuses to silently ignore. The `why` lists the recognized section names, and the file path is in `where.path`. Raised by the engine's needs check, deliberately outside the host-replaceable loader. Meta: none. + +### CLI.CONFIG_UNREADABLE [#CLI.CONFIG_UNREADABLE] + +Evaluating `prisma.config.ts` threw. Two variants share the code: when the error chain shows the `prisma/config` entry point could not be resolved (the prisma package missing from the project, or too old), the guidance is to install the prisma package matching the CLI's version; otherwise the summary carries the first line of the evaluation error and the fix is to repair the file. The path is in `where.path`. Meta: none. + +### CLI.CONFIG_VERSION_UNSUPPORTED [#CLI.CONFIG_VERSION_UNSUPPORTED] + +The config file's `$prismaConfig` marker declares a version other than the one this CLI supports; the fix is to regenerate the config with a matching `definePrismaConfig` or update the CLI. The path is in `where.path`. Meta: none. + +### CLI.CONSENT_REQUIRED [#CLI.CONSENT_REQUIRED] + +A consent prompt was reached under `--yes` or in a non-interactive session. Consent has no default answer and `--yes` does not grant it, so there is nothing for the run to assume. When the consent declares a token, the message and next action say to pass `--confirm `, and the token travels in meta; without a token, the only path is running the command interactively. Meta: `consentToken` (only when the consent declares a token). + +### CLI.CREDENTIALS_LOCKED [#CLI.CREDENTIALS_LOCKED] + +The advisory lock on the stored-credentials file was held by another prisma process for longer than the wait timeout, so this run's credential mutation gave up; the fix is to wait for the other command and retry. Raised by the auth state file's lock helper in `packages/cli`. Meta: none. + +### CLI.CREDENTIALS_REQUIRED [#CLI.CREDENTIALS_REQUIRED] + +The command needs a signed-in credential and none is usable. One constructor covers five reasons: not signed in at all, an expired session, a session expiring too soon for a command that hands credentials to a child process (which cannot refresh them), a workspace session that ended mid-run, and workspace sessions held with none selected as current. Raised identically by the engine's needs check, `ctx.activeCredential`, and the request path; next actions point at signing in or `prisma auth workspace use`. Meta: none. + +### CLI.CREDENTIALS_UNREADABLE [#CLI.CREDENTIALS_UNREADABLE] + +The stored-credentials file exists but could not be read (any read failure other than the file being absent, which yields empty state instead); the guidance is to check the file's permissions. The underlying error is attached as `cause`. Meta: none. + +### CLI.INTERACTION_REQUIRED [#CLI.INTERACTION_REQUIRED] + +The session is not interactive (no TTY stdin, CI, or `--no-interactive`) and the command cannot proceed without a person. Two raise sites: the engine's needs check for a command declaring `needs.interaction`, and `ctx.prompt.browserWait`, which refuses to start a browser wait it could never finish — in that case the URL travels in the error so the user can finish there manually. Meta: `url` (browserWait raise only; none from the needs check). + +### CLI.INTERNAL_ERROR [#CLI.INTERNAL_ERROR] + +A bug, not a user error: a non-structured throw from a handler, an engine invariant violation (undocumented exit code, malformed result), or a stricli internal failure that never settled. The summary is the first line of the underlying error message. Exits 1, the taxonomy's bug code, rather than the usual 2. Meta: none. + +### CLI.INVALID_ARGUMENTS [#CLI.INVALID_ARGUMENTS] + +The invocation's arguments did not parse or contradict each other. Raise sites: stricli's argument-parse failure mapped at the adapter boundary (its usage text becomes summary and `why`), `--config=` given an empty value, `prisma init --skills` given `none` combined with agent names or an unknown agent name, and `prisma skills sync` given both `--disable` and `--enable`. Exits 2 as a usage error. Meta: none. + +### CLI.MISSING_DEPENDENCY [#CLI.MISSING_DEPENDENCY] + +A command declared an optional peer dependency in `needs.dependencies` that does not resolve from the project; the engine probes with `require.resolve` and phrases the install command for the package manager it detected. Meta: `specifier`, `installCommand`. + +### CLI.PACKAGE_MANAGER_FAILED [#CLI.PACKAGE_MANAGER_FAILED] + +A `ctx.packages` operation (an install, or running a package through the manager) exited non-zero — or nothing ran at all because the host wires no package-manager runner, recorded in `meta.reason`. The redacted command line is offered as a run-command next action so the user can run it themselves. Meta: `form`, `manager`, `command`, `exitCode`, `stderrTail`, `reason` (only when the runner is unavailable). + +### CLI.PROMPT_CANCELLED [#CLI.PROMPT_CANCELLED] + +The user cancelled a prompt: EOF on stdin at a line-rendered prompt, a clack cancel (Ctrl-C at the prompt UI), an abort during a browserWait poll, or — via the service commands' `userCancelledError` — consent declined interactively. Settles with exit 3, the cancellation code, instead of 2. Meta: none. + +### CLI.PROMPT_INVALID [#CLI.PROMPT_INVALID] + +An answer could not be interpreted: not a yes/no for a confirm, not one of a select's options with no default to fall back to, or a consent token typed wrong where re-prompting is impossible (scripted answers or piped stdin — the interactive clack renderer re-prompts instead). Meta: `consentToken` (token-mismatch raise only). + +### CLI.PROMPT_REQUIRED [#CLI.PROMPT_REQUIRED] + +A prompt with no declared default was reached where it cannot be shown — under `--yes` or in a non-interactive session — so the run halts; the fix is to run from an interactive terminal or pass a flag that answers the prompt. Meta: none. + +### CLI.SPAWN_FAILED [#CLI.SPAWN_FAILED] + +`ctx.spawn` could not start the requested program, or the child's lifecycle promise rejected; the first line of the underlying failure is in `why`, and the guidance is to check the program is installed and on PATH. Meta: `command`. + +### CLI.TELEMETRY_PREFERENCE_UNAVAILABLE [#CLI.TELEMETRY_PREFERENCE_UNAVAILABLE] + +The `prisma telemetry status|enable|disable` commands could not resolve the user-level config directory because none of XDG_CONFIG_HOME, HOME, APPDATA, or USERPROFILE is set; unreachable in production, where HOME or USERPROFILE is always set. Meta: none. + +### CLI.UNKNOWN_COMMAND [#CLI.UNKNOWN_COMMAND] + +The typed path routed to no command (stricli's route failure, mapped at the adapter boundary) and no redirect claims it; next actions carry up to three "did you mean" suggestions ranked by edit distance over command paths and their prefixes, plus a pointer to `--help`. Exits 2. Meta: none. + +## FEEDBACK + +### FEEDBACK.EMAIL_INVALID [#FEEDBACK.EMAIL_INVALID] + +`prisma feedback --email` was given a value that fails the CLI's local check (a basic address pattern, at most 320 characters), which mirrors the feedback service's own limit so the refusal happens before any network round trip. The suggested actions are to pass a valid address or drop the flag to send anonymously. Meta: none. + +### FEEDBACK.MESSAGE_REQUIRED [#FEEDBACK.MESSAGE_REQUIRED] + +`prisma feedback` was run with a message that is empty after trimming. The fix is to pass a non-empty message. Meta: none. + +### FEEDBACK.MESSAGE_TOO_LONG [#FEEDBACK.MESSAGE_TOO_LONG] + +The `prisma feedback` message exceeds 4000 characters, the feedback service's limit, checked locally before the network round trip; the actual length and the limit are stated in `why`. The fix is to shorten the message. Meta: none. + +### FEEDBACK.SEND_FAILED [#FEEDBACK.SEND_FAILED] + +`prisma feedback` could not deliver the submission: the feedback endpoint was unreachable (or timed out), the service answered a non-OK HTTP status (the status and any service-supplied error message go into `why`), or the response body could not be read; a body that arrived but was not JSON is treated as success, and a user cancellation is rethrown rather than wrapped. The suggested action is to check the network and rerun. Meta: none. + +## GIT + +### GIT.REPO_ALREADY_CONNECTED [#GIT.REPO_ALREADY_CONNECTED] + +`prisma git connect` found the resolved project already connected to a different GitHub repository than the one requested (reconnecting the same repository is idempotent and succeeds). The fix is to run `prisma git disconnect` first. Meta: `repository`. + +### GIT.REPO_CONNECTION_FAILED [#GIT.REPO_CONNECTION_FAILED] + +A management API call in the `prisma git connect`/`disconnect` flow failed — creating the install intent, listing installations or repositories, reading or writing the source-repository connection, or a pagination cursor that stopped advancing; the API's message and hint, when present, become `why` and the suggested fix, and a 401/403 is routed to the auth error path instead. Meta: `status`, `apiCode` (when the API supplied one). + +### GIT.REPO_INSTALLATION_REQUIRED [#GIT.REPO_INSTALLATION_REQUIRED] + +`prisma git connect` waited for a GitHub App installation but the wait ended (timeout or final poll) with the workspace still holding no inspectable installation that could link the repository. The fix is to finish installing the GitHub App at the install URL, then rerun `prisma git connect`; the URL is also offered as an open-url next action. Meta: `repository`, `installUrl`. + +### GIT.REPO_NOT_ACCESSIBLE [#GIT.REPO_NOT_ACCESSIBLE] + +`prisma git connect` waited for repository access but the wait ended with the workspace's existing GitHub App installations still not exposing the requested repository — the same install wait as `GIT.REPO_INSTALLATION_REQUIRED`, distinguished by at least one inspectable installation existing. The fix is to grant the App access to this repository at the install URL, then rerun `prisma git connect`. Meta: `repository`, `installUrl`. + +### GIT.REPO_NOT_CONNECTED [#GIT.REPO_NOT_CONNECTED] + +`prisma git disconnect` found no active GitHub repository connection on the resolved project, so there is nothing to disconnect. The fix is to run `prisma git connect` first. Meta: none. + +### GIT.REPO_PROVIDER_UNSUPPORTED [#GIT.REPO_PROVIDER_UNSUPPORTED] + +The URL given to `prisma git connect` (or read from the local `origin` remote) did not parse as a GitHub repository URL; repository connection supports GitHub only. The fix is to pass a GitHub repository URL. Meta: none. + +### GIT.USAGE_ERROR [#GIT.USAGE_ERROR] + +`prisma git connect` was run with no repository URL argument and the local repository has no `origin` remote to fall back on. The fix is to pass a GitHub repository URL or add a GitHub `origin` remote and rerun. Meta: none. + +## INIT + +### INIT.CONFIG_KEPT [#INIT.CONFIG_KEPT] + +A warn diagnostic from `prisma init`: a `prisma.config.ts` already exists that does not configure `skills.agents`, and init never edits an existing config, so it was left untouched. The nextAction carries the exact `skills: { agents: [...] }` snippet to add to the `definePrismaConfig` call; a config that already sets `skills.agents` produces no diagnostic at all. Meta: none. + +### INIT.CONFIG_UNWRITABLE [#INIT.CONFIG_UNWRITABLE] + +A warn diagnostic from `prisma init`: writing the scaffolded `prisma.config.ts` failed, so the config step was skipped. The nextAction asks the user to create the file themselves with the intended `skills: { agents: [...] }` section. Meta: none. + +### INIT.DEV_DEPENDENCIES_NOT_AN_OBJECT [#INIT.DEV_DEPENDENCIES_NOT_AN_OBJECT] + +A warn diagnostic from `prisma init`: the `devDependencies` field in package.json is not an object, so init did not add the `prisma` dev dependency (the postinstall-hook edit still proceeds when its own field is fine). The nextAction is to fix the field, add `"prisma": ""` by hand, and run the package manager's install. Meta: none. + +### INIT.NO_PACKAGE_JSON [#INIT.NO_PACKAGE_JSON] + +A warn diagnostic from `prisma init`: there is no package.json in the current directory, so neither the skills-sync postinstall hook nor the `prisma` dev dependency was added. The nextActions are to rerun init from the directory that holds package.json, or to add the dependency by hand. Meta: none. + +### INIT.PACKAGE_JSON_UNREADABLE [#INIT.PACKAGE_JSON_UNREADABLE] + +A warn diagnostic from `prisma init`: package.json exists but could not be parsed as JSON, so the postinstall hook and the `prisma` dev dependency were not added. The nextActions give the exact postinstall script and dependency entry to add by hand. Meta: none. + +### INIT.PACKAGE_JSON_UNWRITABLE [#INIT.PACKAGE_JSON_UNWRITABLE] + +A warn diagnostic from `prisma init`: the manifest edit was prepared but writing package.json back failed, so the file was left unchanged. The nextActions cover only what the failed write would have added — the postinstall script, the dev dependency, or both. Meta: none. + +### INIT.POSTINSTALL_KEPT [#INIT.POSTINSTALL_KEPT] + +A warn diagnostic from `prisma init`: package.json already has a postinstall script that is not the CLI's own, and init never overwrites a user's script, so it was left alone. The nextAction is to append `prisma skills sync || exit 0` to the existing script yourself so skills resync on every install. Meta: none. + +### INIT.SCRIPTS_NOT_AN_OBJECT [#INIT.SCRIPTS_NOT_AN_OBJECT] + +A warn diagnostic from `prisma init`: the `scripts` field in package.json is not an object, so init left the manifest untouched instead of adding the postinstall hook (which also skips adding the dev dependency, since the manifest is not edited at all). The nextAction gives the postinstall script to add by hand. Meta: none. + +### INIT.SKILLS_SYNC_FAILED [#INIT.SKILLS_SYNC_FAILED] + +A warn diagnostic from `prisma init`: the final step, syncing the agent skills from installed Prisma packages, threw; the cause's message is appended to the summary. The nextAction is to retry with `prisma skills sync` on its own. Meta: none. + +## POSTGRES + +### POSTGRES.AMBIGUOUS [#POSTGRES.AMBIGUOUS] + +A database name passed to a `prisma postgres` subcommand matched more than one database in the resolved project — raised by the shared database resolver (`controllers/database.ts`). The fix is to pass the database id, or `--branch ` to narrow the match; the candidates are carried in meta as `matches`, each with `id`, `name`, and `branchName`. Meta: `matches`. + +### POSTGRES.API_ERROR [#POSTGRES.API_ERROR] + +A database REST API request failed without a more specific code — the generic fallback for every `prisma postgres` operation, raised by the provider (`lib/database/provider.ts`), and also when a database response omits its project id. The `why` carries the API's message or HTTP status, and the fix is the API's hint when it sent one. An HTTP 401 or 403 raises this code too, with a `why` saying the API rejected the request as unauthorized and a `prisma auth login` next action. Meta: `status`, `apiCode` (the API's own error code, when the response supplied one). + +### POSTGRES.BACKUP_NOT_FOUND [#POSTGRES.BACKUP_NOT_FOUND] + +`prisma postgres backup restore` got a 404 from the restore endpoint; the source and target databases are resolved before the call, so the 404 identifies the backup id. The fix is to pass a backup id from `prisma postgres backup list `. Meta: none. + +### POSTGRES.BACKUPS_UNSUPPORTED [#POSTGRES.BACKUPS_UNSUPPORTED] + +Listing backups returned a 422 because the platform does not manage backups for this database — for example a remote/BYO database (raised by `prisma postgres backup list`). The fix is to use your own backup tooling for externally managed databases. Meta: none. + +### POSTGRES.CONNECTION_MISSING [#POSTGRES.CONNECTION_MISSING] + +`prisma postgres create` created the database, but the API response did not include the first one-time connection payload. The fix is to create a connection explicitly with `prisma postgres connection create `. Meta: none. + +### POSTGRES.CONNECTION_STRING_MISSING [#POSTGRES.CONNECTION_STRING_MISSING] + +A connection create or rotate succeeded, but the API response did not include the one-time connection string the CLI would show exactly once (raised by `prisma postgres create`, `postgres connection create`, and `postgres connection rotate`). The fix is to rerun the operation, or create a replacement connection and store the returned URL immediately. Meta: none. + +### POSTGRES.NOT_FOUND [#POSTGRES.NOT_FOUND] + +The database a `prisma postgres` subcommand targets could not be resolved: either no database matched the given id or name in the project (and optional `--branch`) scope, or a database that was just listed returned 404 on read because it was removed while the command ran (raised by the shared resolver in `controllers/database.ts`). The fix is to pass an id or name from `prisma postgres list`. Meta: none. + +### POSTGRES.PLAN_LIMIT_REACHED [#POSTGRES.PLAN_LIMIT_REACHED] + +A database operation was blocked because the workspace has used up the operations included in its plan — the API's structured plan-limit discriminator, detected on any `prisma postgres` REST API call; this is a workspace plan restriction, not a Prisma outage. The one nextAction is to upgrade the workspace plan, with the upgrade URL and current plan name when the workspace subscription could be read. Meta: `workspaceId`, `blockedFeature`, `planName`, `usageBlocked`, `upgradeUrl` (each `null` when unavailable). + +### POSTGRES.RESTORE_CONFLICT [#POSTGRES.RESTORE_CONFLICT] + +`prisma postgres backup restore` got a 409 because the target database is provisioning or already recovering. The fix is to wait for the database to become ready — check with `prisma postgres show ` — then retry. Meta: none. + +### POSTGRES.USAGE_ERROR [#POSTGRES.USAGE_ERROR] + +A `prisma postgres` subcommand was called with missing or invalid arguments: `create` without a name, `connection delete`/`connection rotate` without a connection id, `backup restore` without `--backup`, or `usage` with `--from` later than `--to`. The nextActions show the corrected command form. Meta: none. + +## PROJECT + +### PROJECT.AMBIGUOUS [#PROJECT.AMBIGUOUS] + +Project resolution matched more than one project: an explicit project reference (matched by id first, then by name) hit several projects, or the implicit directory context did — raised by any command that resolves a project, including `branch list`. The fix is to pass `--project `, and the next actions include `prisma project link ` with the first match's id verbatim so the user can copy an exact disambiguating reference. Meta: `matches`. + +### PROJECT.API_ERROR [#PROJECT.API_ERROR] + +A REST API project operation (list, rename, delete, or transfer) failed. Listing projects deliberately throws this rather than returning an empty list, so a rejected request is distinguishable from a workspace that genuinely has no projects. The `why` carries the API's message or HTTP status, and the API's own error code, when it sent one, is in `meta.apiCode`. Meta: `status`, `apiCode` (each present only when the response supplied it). + +### PROJECT.CREATE_FAILED [#PROJECT.CREATE_FAILED] + +The platform rejected creating a project — raised by `prisma project create` and by the create-a-new-project path of `prisma project link`. An HTTP 401/403 gets a permissions-focused fix; any other failure surfaces the underlying error message as the `why`. Meta: none. + +### PROJECT.DELETE_BLOCKED [#PROJECT.DELETE_BLOCKED] + +The REST API answered `prisma project delete` with HTTP 400, which typically means the project still has active deployments; the fix is to delete the project's services first (`prisma service delete --service `) and retry. The API's own message replaces the default `why` when present. Meta: none. + +### PROJECT.ENV_API_ERROR [#PROJECT.ENV_API_ERROR] + +A REST API call made by the `prisma project env` commands (reading, writing, or deleting variables, or resolving and creating branches for a scope) failed. The summary names the call that failed, for example "Failed to add STRIPE_KEY". An HTTP 401 or 403 raises this code too, with a `why` saying the API rejected the request as unauthorized and a `prisma auth login` next action. Meta: `status`, `apiCode` (the API's own error code, when the response supplied one). + +### PROJECT.ENV_BRANCH_CREATE_REQUIRES_DEFAULT_BRANCH [#PROJECT.ENV_BRANCH_CREATE_REQUIRES_DEFAULT_BRANCH] + +`prisma project env add --branch ` will create a missing preview branch, but the project has no default branch yet, and creating the first branch would make it the default while branch env overrides are preview-only. The fix is to create or deploy the default branch first, for example via `prisma git connect`. Meta: none. + +### PROJECT.ENV_BRANCH_NOT_FOUND [#PROJECT.ENV_BRANCH_NOT_FOUND] + +A `prisma project env` update, list, or delete named a branch scope (`--branch `) that does not exist — only `env add` creates missing branches. The fix is to create the branch by deploying it, or to use `project env add --branch` to create its first override. Meta: none. + +### PROJECT.ENV_BRANCH_SCOPE_IS_PRODUCTION [#PROJECT.ENV_BRANCH_SCOPE_IS_PRODUCTION] + +A `prisma project env` command's `--branch` flag resolved to the project's production branch; production variables are project-level only, and branch overrides apply to preview branches. The fix is to use `--role production` instead. Meta: none. + +### PROJECT.ENV_FILE_APPLY_FAILED [#PROJECT.ENV_FILE_APPLY_FAILED] + +`prisma project env add --file` or `update --file` failed while writing one of the file's keys, after zero or more earlier keys were already written. The `why` names the keys written before the failure and the underlying cause, and the next actions include a retry command scoped to a file of the remaining keys. Meta: `file`, `failedKey`, `writtenKeys`. + +### PROJECT.ENV_PREVIEW_DEFAULT_MISSING [#PROJECT.ENV_PREVIEW_DEFAULT_MISSING] + +Not an error: a warn diagnostic emitted on a successful `prisma project env add` to a branch scope (single key or `--file`) for each key that has no preview-level default, meaning the variable will exist only on that branch. Meta: none. + +### PROJECT.ENV_VARIABLE_ALREADY_EXISTS [#PROJECT.ENV_VARIABLE_ALREADY_EXISTS] + +`prisma project env add` targeted a key (or, in `--file` mode, one or more keys) that already exists in the targeted scope. The single-key fix is to use `prisma project env update`; the file-mode fix is to split the input file and update existing keys separately from adding new ones. Meta: `keys` (file mode only; the single-key form carries no meta). + +### PROJECT.ENV_VARIABLE_NOT_FOUND [#PROJECT.ENV_VARIABLE_NOT_FOUND] + +`prisma project env update` or `env delete` targeted a key (or, in update's `--file` mode, one or more keys) that does not exist in the targeted scope. The fix for update is to create the variable with `env add` (or split a mixed file); for delete it is to list the scope's variables first. Meta: `keys` (file-mode update only; the single-key forms carry no meta). + +### PROJECT.LOCAL_STATE_STALE [#PROJECT.LOCAL_STATE_STALE] + +The local project binding in `.prisma/local.json` is unusable: the pinned project is no longer in the selected workspace's project list, or the pin file is invalid JSON or has an invalid shape — raised by any command that resolves the project implicitly through the pin. The fix is to delete the pin file and choose a project explicitly. Meta: `pinPath`. + +### PROJECT.LOCAL_STATE_WRITE_FAILED [#PROJECT.LOCAL_STATE_WRITE_FAILED] + +`prisma project link` or `project create` could not save the local binding: writing `.prisma/local.json` failed, or updating `.gitignore` to keep the binding out of git failed — the fix is to check directory permissions and retry. The same code is also emitted as a warn diagnostic (not an error) by `project delete` and `project transfer` when the operation itself succeeded but the now-stale local pin could not be removed or rewritten. Meta: `pinPath` or `gitignorePath`, plus `operation` (the error form; the diagnostic form carries none). + +### PROJECT.LOCAL_WORKSPACE_MISMATCH [#PROJECT.LOCAL_WORKSPACE_MISMATCH] + +`.prisma/local.json` links the directory to a project in one workspace, but the CLI session's active workspace is a different one — raised by any command that resolves the project through the pin. The fix is to switch to the pinned workspace (`prisma auth workspace use `) or relink the directory to a project in the current workspace. Meta: `pinPath`, `pinnedWorkspaceId`, `pinnedProjectId`, `activeWorkspaceId`, `activeWorkspaceName`. + +### PROJECT.NOT_FOUND [#PROJECT.NOT_FOUND] + +An explicit project reference matched no project in the active workspace, either because it does not exist or because the credential cannot see it — raised during project resolution for any command that accepts one, including `branch list` and the `project link`/`transfer`/`delete` target lookup. The fix is to pass an id or name from `prisma project list`. Meta: none. + +### PROJECT.RENAME_FAILED [#PROJECT.RENAME_FAILED] + +The REST API answered `prisma project rename` with HTTP 400 or 422, meaning the platform rejected the new name; the API's message and hint replace the default `why` and fix when present, and the fallback fix is to retry with a different name. Meta: none. + +### PROJECT.SETUP_REQUIRED [#PROJECT.SETUP_REQUIRED] + +A command needed a project but the directory is not linked and no `--project` flag was given; the CLI deliberately refuses to pick a project from package or directory names, treating them as suggestions only. The meta carries the inferred name suggestion and any matching candidate projects, and the next actions walk through choosing between linking an existing project (`prisma project link`) and creating a new one. Meta: `suggestedProjectName`, `suggestedProjectNameSource`, `candidates`, `recoveryCommands`. + +### PROJECT.TRANSFER_RECIPIENT_REQUIRED [#PROJECT.TRANSFER_RECIPIENT_REQUIRED] + +`prisma project transfer` was invoked without naming a receiving workspace: neither `--to-workspace ` (for a locally authenticated workspace) nor `--recipient-token ` (for a cross-account transfer) was passed. Meta: none. + +### PROJECT.TRANSFER_RECIPIENT_UNAVAILABLE [#PROJECT.TRANSFER_RECIPIENT_UNAVAILABLE] + +`prisma project transfer --to-workspace` needs to resolve locally stored OAuth workspace sessions, but `PRISMA_SERVICE_TOKEN` is set and service-token mode does not read them. The fix is to pass `--recipient-token ` for the receiving workspace, or to unset the service token. Meta: none. + +### PROJECT.TRANSFER_REJECTED [#PROJECT.TRANSFER_REJECTED] + +The REST API answered `prisma project transfer` with HTTP 400 — for example because the recipient token is invalid or expired; the API's message replaces the default `why` when present, and the fix is to check the recipient session or token and retry. Meta: none. + +### PROJECT.USAGE_ERROR [#PROJECT.USAGE_ERROR] + +A `project` or `branch` group command was invoked with unusable arguments — for example a `project env` write without an explicit `--role` or `--branch` scope, `project transfer` with both recipient flags at once, `project create` with an empty name, or an interactive `project link` whose selection was cancelled. Usage errors exit 2. Meta: none. + +## SERVICE + +### SERVICE.BRANCH_INVALID [#SERVICE.BRANCH_INVALID] + +A `--branch` flag was passed with an empty or whitespace-only value to a service command; the check runs before any resolution because a blank value must never fall through to the default-branch behavior of omitting the flag. The fix is to pass a non-empty branch name, or omit `--branch` to target the default branch. Meta: none. + +### SERVICE.BRANCH_NOT_DEPLOYABLE [#SERVICE.BRANCH_NOT_DEPLOYABLE] + +A `service domain` command was pointed at a non-production branch, which the domain-target resolver refuses because custom domains on preview branches are not supported in Public Beta. The fix is to use `--branch production`, or attach the domain after promoting to the production branch. Meta: none. + +### SERVICE.DELETE_FAILED [#SERVICE.DELETE_FAILED] + +`service delete` called the platform's app-teardown API and it rejected; the underlying error's message becomes `why` and the original error is carried in `cause`. Next actions point at `service show` and `service version list` for the service. Meta: none. + +### SERVICE.DEPLOY_FAILED [#SERVICE.DEPLOY_FAILED] + +The general "REST API call failed" wrapper for the `service` command family — despite the name there is no deploy command here: it wraps failures to create a service, list services or versions, show/promote/roll back/delete/start/stop a version, resolve a service URL, and unrecognized custom-domain API failures. The underlying error's message becomes `why` and the original error is carried in `cause`; each raise site attaches its own next actions. On the domain fallback path only, a `DomainApiError` adds debug meta. Meta: `status`, `apiCode`, `hint` (domain fallback path only; otherwise none). + +### SERVICE.DOMAIN_ALREADY_REGISTERED [#SERVICE.DOMAIN_ALREADY_REGISTERED] + +`service domain add` got HTTP 409 from the domain API because the hostname is already registered, to this or another service. The fix is to delete the domain on the service that owns it, or contact Prisma support if that service is not accessible. Meta: `status`, `apiCode`, `hint`. + +### SERVICE.DOMAIN_DNS_NOT_CONFIGURED [#SERVICE.DOMAIN_DNS_NOT_CONFIGURED] + +`service domain add` got HTTP 400 or 422 whose message the CLI recognizes as a DNS problem (no CNAME, DNS verification failed, and similar). When the API's text names a `*.prisma.build` target, the CLI composes the exact CNAME record to add and carries it in `meta.dnsRecord` and in the advice action; without a target it advises rerunning with `--log-level verbose` to see the API response. Meta: `status`, `apiCode`, `hint`, `dnsRecord` (when the DNS target could be extracted). + +### SERVICE.DOMAIN_HOSTNAME_INVALID [#SERVICE.DOMAIN_HOSTNAME_INVALID] + +The hostname given to a `service domain` command is not a usable custom domain — raised either by local validation before any API call (protocol, path, port, wildcard, single label, or bad DNS labels) or when `service domain add` gets a plain HTTP 400 rejection from the domain API. The fix is to pass a bare hostname such as `shop.acme.com`. Meta: `status`, `apiCode`, `hint` (API-rejection path only; none for local validation). + +### SERVICE.DOMAIN_NOT_FOUND [#SERVICE.DOMAIN_NOT_FOUND] + +A `service domain` command targeted a hostname that is not attached to the resolved service — raised when the service's domain listing has no matching hostname, or when a show/delete/retry/wait call gets HTTP 404. The fix is to check the hostname and service, or add the domain first. Meta: none. + +### SERVICE.DOMAIN_QUOTA_EXCEEDED [#SERVICE.DOMAIN_QUOTA_EXCEEDED] + +`service domain add` was refused because the custom-domain quota is reached — HTTP 429, or a 409 whose text mentions a quota, maximum, or limit. The fix is to delete an existing custom domain before adding another. Meta: `status`, `apiCode`, `hint`. + +### SERVICE.DOMAIN_RETRY_NOT_ELIGIBLE [#SERVICE.DOMAIN_RETRY_NOT_ELIGIBLE] + +`service domain retry` got HTTP 409: the domain is not in a state that can be retried, typically because a verification or TLS step is still in progress. The fix is to wait for the current step to finish and retry only if the domain then fails. Meta: `status`, `apiCode`, `hint`. + +### SERVICE.DOMAIN_VERIFICATION_FAILED [#SERVICE.DOMAIN_VERIFICATION_FAILED] + +`service domain wait` observed the domain reach the terminal `failed` status; `why` carries the platform's failure category and reason when reported, and a failure-specific fix line is attached when the CLI can derive one from the domain record. Next actions point at `service domain show` and `service domain retry`. Meta: none. + +### SERVICE.DOMAIN_VERIFICATION_TIMEOUT [#SERVICE.DOMAIN_VERIFICATION_TIMEOUT] + +`service domain wait` ran out of time (default 15m, or `--timeout 0` for a single check) before the domain became active; `why` reports the status the domain was last seen in. The fix is to inspect the domain with `service domain show` or rerun the wait with a longer `--timeout`. Meta: none. + +### SERVICE.FEATURE_UNAVAILABLE [#SERVICE.FEATURE_UNAVAILABLE] + +`service open` found a live version but the provider does not expose a stable live service URL for this service yet, so there is nothing to open. The next action is to inspect the service state with `service show`. Meta: none. + +### SERVICE.LIVE_VERSION_UNKNOWN [#SERVICE.LIVE_VERSION_UNKNOWN] + +`service version rollback` without `--to` needs to know which version is live, because the default rollback target is defined relative to it, and the service record names no live version — the CLI refuses rather than guess what production is serving. The fix is to pass `--to ` explicitly. Meta: none. + +### SERVICE.LOGS_FAILED [#SERVICE.LOGS_FAILED] + +`service logs` could not read the log — either the logs endpoint answered with a non-OK HTTP status (other than 404, which becomes SERVICE.VERSION_NOT_FOUND), or a page's closing terminal record reported `kind: "error"`, meaning the platform itself says the log read failed. The meta differs by path: the HTTP path carries `status`; the terminal-record path carries the platform's error `code`, `retryable`, and the resume `cursor` when present (in `--follow` mode one retryable terminal error is retried once before this settles the run). Meta: `status` (HTTP path) or `code`, `retryable`, `cursor` (stream path). + +### SERVICE.LOGS_INCOMPLETE [#SERVICE.LOGS_INCOMPLETE] + +A `service logs` response body ended without the terminal record that closes a page, so the read was truncated and the lines already printed may be only part of the page; the run must not settle as if it had read the whole page. Distinct from SERVICE.LOGS_NO_CURSOR, which is a properly closed page with nothing to resume from. The fix is to rerun the command. Meta: none. + +### SERVICE.LOGS_NO_CURSOR [#SERVICE.LOGS_NO_CURSOR] + +`service logs --follow` needs a resume cursor from each page to fetch the next one, and the page ended without one — continuing would re-request the default tail and silently print the same lines every interval, so the run stops and says why. It settles as an error rather than a clean end because `--follow` has no successful ending. The fix is to rerun without `--follow`, or retry if the version is still starting. Meta: none. + +### SERVICE.LOGS_RANGE_CONFLICT [#SERVICE.LOGS_RANGE_CONFLICT] + +`service logs` was invoked with both `--tail` and `--from-start`, which ask for opposite ends of the log; the run is refused before any work. The fix is to pass `--tail ` for the last n lines or `--from-start` for the whole log, not both. Meta: none. + +### SERVICE.NAME_REQUIRED [#SERVICE.NAME_REQUIRED] + +`service create` received an empty or whitespace-only name positional; the check runs before any resolution. The fix is to pass a name, as in `service create my-service`. Meta: none. + +### SERVICE.NO_PREVIOUS_VERSION [#SERVICE.NO_PREVIOUS_VERSION] + +`service version rollback` without `--to` found no earlier version to switch back to — the service has no versions at all, or every version is the live one. The fix is to deploy a second version first, or pass `--to ` for a specific version. Meta: none. + +### SERVICE.NO_VERSIONS [#SERVICE.NO_VERSIONS] + +The resolved service has no usable version for the command — raised by `service open` when the service has no versions, by `service logs` when it has no live version, and by `service domain add` when the API answers 422 because the production service has no promoted version that can receive a custom domain. The fix on the domain path is to promote a version on the production branch first, then add the domain again. Meta: `status`, `apiCode`, `hint` (domain-add path only; otherwise none). + +### SERVICE.PROJECT_NOT_FOUND [#SERVICE.PROJECT_NOT_FOUND] + +The project a service command resolved to does not exist in the authenticated workspace or is no longer accessible — raised when listing services answers "Resource Not Found" for the resolved project id. A service command that cannot match an explicit `--project` reference fails with the project group's own `PROJECT.NOT_FOUND` instead, because the condition is the same one whichever command met it. Next actions point at `project show` to inspect the directory binding and `project link` to fix it. Meta: none. + +### SERVICE.SELECTION_INVALID [#SERVICE.SELECTION_INVALID] + +The named service could not be found among the resolved project branch's services — the match tries the stable platform id first, then the name. The fix is to pass the id or name of an existing service; the suggested command is `service list`, deliberately not `service version list`, which itself has to resolve a service and would fail the same way. Meta: none. + +### SERVICE.TARGET_REQUIRED [#SERVICE.TARGET_REQUIRED] + +A service command that acts on an existing service was run without naming one; service commands act only on an explicitly named target — nothing is inferred, remembered, or prompted for. The fix is to pass the service id or name as the first argument, with `service list` to find one. Meta: none. + +### SERVICE.TIMEOUT_INVALID [#SERVICE.TIMEOUT_INVALID] + +The `--timeout` value passed to `service domain wait` is not a duration the parser accepts (`0`, or an integer with `ms`/`s`/`m`/`h`, such as `30s` or `15m`). Meta: none. + +### SERVICE.VERSION_ALREADY_LIVE [#SERVICE.VERSION_ALREADY_LIVE] + +Not an error: a warn-severity diagnostic attached by `service version promote` and `service version rollback` when the selected version is already live for the service — the command skips the promote call, still reports the result, and exits 0. Meta: none. + +### SERVICE.VERSION_ALREADY_RUNNING [#SERVICE.VERSION_ALREADY_RUNNING] + +Not an error: a warn-severity diagnostic attached by `service version start` when the selected version already reports `running` status — the start call is skipped, the result carries `alreadyInState: true`, and the run exits 0. Meta: none. + +### SERVICE.VERSION_ALREADY_STOPPED [#SERVICE.VERSION_ALREADY_STOPPED] + +Not an error: a warn-severity diagnostic attached by `service version stop` when the selected version already reports `stopped` status — the stop call is skipped, the result carries `alreadyInState: true`, and the run exits 0. Meta: none. + +### SERVICE.VERSION_DETACHED [#SERVICE.VERSION_DETACHED] + +A version was resolved by its globally-unique id but the REST API returned it without an owning service, so there is nothing to report or act on it as. The next action shows the version with `service version show`. Meta: none. + +### SERVICE.VERSION_NOT_FOUND [#SERVICE.VERSION_NOT_FOUND] + +The requested service version does not exist or is not available — raised when resolving a version by its globally-unique id finds nothing (including a 404 from the logs endpoint), and, in the "for service" variant used by rollback and logs `--version-id`, when the id exists but does not belong to the resolved service. The fix is to pick an id from `service version list`. Meta: none. + +### SERVICE.WORKSPACE_REQUIRED [#SERVICE.WORKSPACE_REQUIRED] + +A service command ran without a credential that names a workspace — either no authenticated session, or an environment token whose claims carry no workspace, which cannot scope these commands and is treated the same as having no credential. The fix is `auth login`. Meta: none. + +## SKILLS + +### SKILLS.CONFIG_INVALID [#SKILLS.CONFIG_INVALID] + +An error diagnostic from validating the `skills` section of `prisma.config.ts`, surfaced by the commands that consume it (`init`, `skills sync`, `skills list`): the section is not an object, `skills.check` is not a boolean, `skills.agents` is not an array of strings, or an agent name is one this CLI does not know. Each variant's nextAction says what to write instead; code that reads the config outside a command handler (the staleness check, the post-login tip) treats an invalid config as absent and falls back to the default agent set rather than silencing the check. Meta: none. + +### SKILLS.UNMANAGED_DIRECTORY [#SKILLS.UNMANAGED_DIRECTORY] + +A warn diagnostic from the skills sync (`skills sync`, and the sync step of `init`): a target agent skill directory already holds a skill this CLI does not manage, so sync left it untouched instead of installing the packaged skill there. The nextAction is to move or remove the unmanaged directory and rerun `skills sync`. Meta: none. + +### SKILLS.VERSION_CONFLICT [#SKILLS.VERSION_CONFLICT] + +A warn diagnostic from the skills sync (`skills sync`, and the sync step of `init`): workspace members install different versions of the same skill-bearing Prisma package, so the skills for the highest version were installed and the members pinning a lower version get a skill describing a version they did not install. The nextAction is to pin one version of the package across the workspace. Meta: none. diff --git a/apps/docs/content/docs/cli/meta.json b/apps/docs/content/docs/cli/meta.json index 0619bd66af..1ef27f909f 100644 --- a/apps/docs/content/docs/cli/meta.json +++ b/apps/docs/content/docs/cli/meta.json @@ -8,6 +8,7 @@ "v7", "global-flags", "configuration", + "error-reference", "---Platform---", "auth", "branch", diff --git a/apps/docs/content/docs/orm/reference/error-reference.mdx b/apps/docs/content/docs/orm/reference/error-reference.mdx index 7f8b475970..321c367d69 100644 --- a/apps/docs/content/docs/orm/reference/error-reference.mdx +++ b/apps/docs/content/docs/orm/reference/error-reference.mdx @@ -1,9 +1,9 @@ --- title: Error reference -description: 'Every structured error code Prisma 8 can emit, by namespace, with the condition that raises it.' +description: Every structured error code Prisma 8 can emit, by namespace, with the condition that raises it. url: /orm/reference/error-reference metaTitle: Prisma 8 error reference -metaDescription: 'Every structured error code Prisma 8 can emit, by namespace, with the condition that raises it.' +metaDescription: Every structured error code Prisma 8 can emit, by namespace, with the condition that raises it. --- {/* Generated by scripts/generate-error-reference.mjs from @@ -25,7 +25,7 @@ Codes that predate the dotted scheme were renamed at 0.16; the full old→new cr Namespaces: | Namespace | Covers | -|---|---| +| --- | --- | | `CONFIG` | Loading and validating `prisma.config.ts` | | `CLI` | Command-line argument and invocation errors | | `CONTRACT` | Contract authoring, emission, validation, and the contract↔database relationship (markers, schema verification) | @@ -49,11 +49,11 @@ The `contract` section is missing (or incomplete) in `prisma.config.ts` when a c ### CONFIG.DB_CONNECTION_REQUIRED [#CONFIG.DB_CONNECTION_REQUIRED] -A DB-connected command (`db migrate`, `db init`, `db sign`, `db verify`, `db update`, `inspect-live-schema`, and the migration scaffold commands) was run with no database connection available — no `--db ` flag and no `db.connection` in `prisma.config.ts`. The fix text names the exact retry command when known. Meta: `missingFlags` (optional). +A DB-connected command (`migrate`, `db init`, `db sign`, `db verify`, `db update`, `inspect-live-schema`, and the migration scaffold commands) was run with no database connection available — no `--db ` flag and no `db.connection` in `prisma.config.ts`. The fix text names the exact retry command when known. Meta: `missingFlags` (optional). ### CONFIG.DRIVER_REQUIRED [#CONFIG.DRIVER_REQUIRED] -A DB-connected command was run but `prisma.config.ts` has no control-plane `driver` entry (e.g. `driver: postgresDriver`). Raised by the migration command scaffold, `db migrate`, `db sign`, `db verify`, and `inspect-live-schema`. Meta: none. +A DB-connected command was run but `prisma.config.ts` has no control-plane `driver` entry (e.g. `driver: postgresDriver`). Raised by the migration command scaffold, `migrate`, `db sign`, `db verify`, and `inspect-live-schema`. Meta: none. ### CONFIG.EVALUATION_FAILED [#CONFIG.EVALUATION_FAILED] @@ -103,7 +103,7 @@ The migration-file CLI (`prisma migration`) received `--config` without a path a ### CLI.FILE_NOT_FOUND [#CLI.FILE_NOT_FOUND] -A file the command needs does not exist at the given path. Produced by several commands: the migration command scaffold, `db migrate`, `migration plan`, `migration show`, `db sign`, `db update`, `db verify`, and `migration ref` all raise it when the emitted `contract.json` (or another required file) is missing from the expected location. Most sites carry the path in `where.path`; the `migration new` contract-file site carries it in the summary text only. Meta: none. +A file the command needs does not exist at the given path. Produced by several commands: the migration command scaffold, `migrate`, `migration plan`, `migration show`, `db sign`, `db update`, `db verify`, and `ref` all raise it when the emitted `contract.json` (or another required file) is missing from the expected location. Most sites carry the path in `where.path`; the `migration new` contract-file site carries it in the summary text only. Meta: none. ### CLI.FILE_WRITE_FAILED [#CLI.FILE_WRITE_FAILED] @@ -525,7 +525,7 @@ A mutation that expected the database to return a row got none — `create()`/`u ### ORM.OPERATION_UNSUPPORTED [#ORM.OPERATION_UNSUPPORTED] -A valid ORM method was called in a configuration that does not support it: mutating an MTI variant collection with a method that requires `createAll()`, Mongo `upsert()` with dot-path field operations, or a Mongo mutation carrying windowing (`orderBy`/`skip`/`take`) or includes. Meta: `method`, `model`, `reason`, `field`. +A valid ORM method was called in a configuration that does not support it: mutating an MTI variant collection with a method that requires `createAll()`, Mongo `upsert()` with dot-path field operations, or a Mongo mutation carrying windowing (`orderBy`/`offset`/`limit`) or includes. Meta: `method`, `model`, `reason`, `field`. ### ORM.RELATION_LINK_DUPLICATE [#ORM.RELATION_LINK_DUPLICATE] @@ -818,7 +818,7 @@ A `migration check` finding, carried as an `error` diagnostic on a completed run ### MIGRATION.CHECK_DANGLING_REF [#MIGRATION.CHECK_DANGLING_REF] -A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: a ref file points at a contract hash that does not exist in the space's migration graph. Update the ref with `prisma migration ref set ` or delete it. +A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: a ref file points at a contract hash that does not exist in the space's migration graph. Update the ref with `prisma ref set ` or delete it. ### MIGRATION.CHECK_DECLARED_BUT_UNMIGRATED [#MIGRATION.CHECK_DECLARED_BUT_UNMIGRATED] @@ -926,7 +926,7 @@ An extension descriptor publishes a `contractSpace` whose `headRef.hash` does no ### MIGRATION.DESTINATION_CONTRACT_MISMATCH [#MIGRATION.DESTINATION_CONTRACT_MISMATCH] -Runner-level failure during apply (`db init`, `db update`, `db migrate`): the plan's destination storage hash (or profile hash) does not match the destination contract handed to the runner alongside it. Indicates the plan and contract came from different emits. Meta: `planStorageHash`/`contractStorageHash` (or `planProfileHash`/`contractProfileHash`). +Runner-level failure during apply (`db init`, `db update`, `migrate`): the plan's destination storage hash (or profile hash) does not match the destination contract handed to the runner alongside it. Indicates the plan and contract came from different emits. Meta: `planStorageHash`/`contractStorageHash` (or `planProfileHash`/`contractProfileHash`). ### MIGRATION.DESTRUCTIVE_CHANGES [#MIGRATION.DESTRUCTIVE_CHANGES] @@ -950,7 +950,7 @@ The per-space migration planner received the same contract-space id more than on ### MIGRATION.EXECUTION_FAILED [#MIGRATION.EXECUTION_FAILED] -A migration operation's SQL step failed while being executed against the database during apply (`db init`, `db update`, `db migrate`). The envelope carries the database error detail so you can see which statement failed and why. Meta: `operationId`, `stepDescription`, `sql`, `sqlState`, `constraint`, `table`, `column`, `detail`. +A migration operation's SQL step failed while being executed against the database during apply (`db init`, `db update`, `migrate`). The envelope carries the database error detail so you can see which statement failed and why. Meta: `operationId`, `stepDescription`, `sql`, `sqlState`, `constraint`, `table`, `column`, `detail`. ### MIGRATION.FILE_MISSING [#MIGRATION.FILE_MISSING] @@ -1054,7 +1054,7 @@ While reconstructing the migration graph, no migration starts from the empty con ### MIGRATION.NO_INVARIANT_PATH [#MIGRATION.NO_INVARIANT_PATH] -The target (or named ref) requires data invariants, and no path through the migration graph from the current state covers all of them. Add a migration on the path that runs a `dataTransform` with each missing `invariantId`, or retarget the ref. Meta: `required`, `missing`, `structuralPath` (edges: `dirName`, `migrationHash`, `from`, `to`, `invariants`), `refName` (when applicable). Also raised per space by `db migrate` in show/plan mode when a space's path requires invariants not available on disk; that site's meta is `spaceId`, `missing`. +The target (or named ref) requires data invariants, and no path through the migration graph from the current state covers all of them. Add a migration on the path that runs a `dataTransform` with each missing `invariantId`, or retarget the ref. Meta: `required`, `missing`, `structuralPath` (edges: `dirName`, `migrationHash`, `from`, `to`, `invariants`), `refName` (when applicable). Also raised per space by `migrate` in show/plan mode when a space's path requires invariants not available on disk; that site's meta is `spaceId`, `missing`. ### MIGRATION.NO_MIGRATIONS [#MIGRATION.NO_MIGRATIONS] @@ -1074,7 +1074,7 @@ A Mongo migration check uses a filter feature the check evaluator does not suppo ### MIGRATION.PATH_UNREACHABLE [#MIGRATION.PATH_UNREACHABLE] -An apply command (`db migrate`/`db update`) cannot find a path through the on-disk migration graph from the database's current marker to the requested target — the connecting edge was never planned. The fix walks you through `migration plan` (with the right `--from`/`--to`) then `db migrate`. Meta: carries the underlying failure's meta (`fromHash`, `targetHash`, `deadEnds`, `kind`). +An apply command (`migrate`/`db update`) cannot find a path through the on-disk migration graph from the database's current marker to the requested target — the connecting edge was never planned. The fix walks you through `migration plan` (with the right `--from`/`--to`) then `migrate`. Meta: carries the underlying failure's meta (`fromHash`, `targetHash`, `deadEnds`, `kind`). ### MIGRATION.PLANNING_FAILED [#MIGRATION.PLANNING_FAILED] @@ -1084,6 +1084,10 @@ Migration planning (typically during `db init`/`db update`) failed because of co An authored migration's `operations` getter returned something other than an array. Fix the migration class so `operations` returns an array of operations. Meta: `dir`, `actualValue` (when known). +### MIGRATION.PLAN_ORIGIN_UNKNOWN [#MIGRATION.PLAN_ORIGIN_UNKNOWN] + +`migration plan` was run without `--from` and without a `db` ref while migrations already exist on disk. Planning would silently fall back to an empty-database origin and produce a migration that recreates everything the existing history already creates, so the command refuses. Set the `db` ref (`migration ref set db ` or `db update`), pass `--from `, or pass `--from @empty` to deliberately plan from an empty database. Meta: `reachableRefs`, `graphTipHash` (when the graph has a tip). + ### MIGRATION.POLICY_VIOLATION [#MIGRATION.POLICY_VIOLATION] A planned operation's class (e.g. `destructive`) is not allowed by the execution-time operation policy in force for the command. Runner-level failure during apply. Meta: `operationId`, `operationClass`, `allowedClasses`. @@ -1134,7 +1138,7 @@ A reference parsed, but as the wrong kind for the argument position — e.g. a m ### MIGRATION.RUNNER_FAILED [#MIGRATION.RUNNER_FAILED] -Generic wrapper for a migration runner failure during execution that has no more specific code; the summary/why carry the underlying detail (also used to surface the legacy-marker-shape condition from marker reads, with `meta.runnerErrorCode`). `db migrate` and `db init` map unrecognized apply failures through it, passing the failure's own meta through unchanged. Inspect the reported summary/why detail and address the underlying failure before re-running the command. Meta: the wrapped failure's meta, when it has any; `runnerErrorCode` at the legacy-marker-shape site. +Generic wrapper for a migration runner failure during execution that has no more specific code; the summary/why carry the underlying detail (also used to surface the legacy-marker-shape condition from marker reads, with `meta.runnerErrorCode`). `migrate` and `db init` map unrecognized apply failures through it, passing the failure's own meta through unchanged. Inspect the reported summary/why detail and address the underlying failure before re-running the command. Meta: the wrapped failure's meta, when it has any; `runnerErrorCode` at the legacy-marker-shape site. ### MIGRATION.SAME_SOURCE_AND_TARGET [#MIGRATION.SAME_SOURCE_AND_TARGET] @@ -1142,7 +1146,7 @@ A migration's `from` and `to` hashes are identical and it declares no data-trans ### MIGRATION.SCHEMA_VERIFY_FAILED [#MIGRATION.SCHEMA_VERIFY_FAILED] -After applying migrations, the runner introspected the database and the resulting schema does not satisfy the destination contract; the apply is rolled back. Runner-level failure during `db init`/`db update`/`db migrate`. Meta: `issues` (schema diff issues). +After applying migrations, the runner introspected the database and the resulting schema does not satisfy the destination contract; the apply is rolled back. Runner-level failure during `db init`/`db update`/`migrate`. Meta: `issues` (schema diff issues). ### MIGRATION.SNAPSHOT_MISSING [#MIGRATION.SNAPSHOT_MISSING] @@ -1178,7 +1182,7 @@ A ref declares required invariants that no migration anywhere in the graph provi ### MIGRATION.UNKNOWN_REF [#MIGRATION.UNKNOWN_REF] -A ref name was used (read, resolved, or deleted via `ref` commands) but no ref file with that name exists. Create it with `prisma migration ref set `, or run `prisma migration ref list` to see what exists. Meta: `refName`, `filePath` or `availableRefs` depending on the site. +A ref name was used (read, resolved, or deleted via `ref` commands) but no ref file with that name exists. Create it with `prisma ref set `, or run `ref list` to see what exists. Meta: `refName`, `filePath` or `availableRefs` depending on the site. ## PLAN diff --git a/apps/docs/cspell.json b/apps/docs/cspell.json index cfd922d7dc..4278331adc 100644 --- a/apps/docs/cspell.json +++ b/apps/docs/cspell.json @@ -367,6 +367,7 @@ "streamable", "streamdal", "Streamdal", + "stricli", "subclassing", "Subtacts", "Sunsetting", @@ -425,6 +426,7 @@ "UNLOADABLE", "unmigrated", "UNPARSEABLE", + "UNWRITABLE", "unparseable", "untick", "UPLOADTHING", diff --git a/apps/docs/next.config.mjs b/apps/docs/next.config.mjs index dbfd9fc5fc..7c4928b425 100644 --- a/apps/docs/next.config.mjs +++ b/apps/docs/next.config.mjs @@ -310,7 +310,11 @@ const config = { permanent: true, }, { source: "/v8/:path*", destination: "/prisma-orm", permanent: true }, - { source: "/orm/v8/create-prisma", destination: "/prisma-orm/create-prisma", permanent: true }, + { + source: "/orm/v8/create-prisma", + destination: "/prisma-orm/create-prisma", + permanent: true, + }, { source: "/orm/v8/quickstart/:path*", destination: "/prisma-orm/quickstart/:path*", @@ -362,7 +366,11 @@ const config = { permanent: true, }, { source: "/next/:path*", destination: "/prisma-orm", permanent: true }, - { source: "/orm/next/create-prisma", destination: "/prisma-orm/create-prisma", permanent: true }, + { + source: "/orm/next/create-prisma", + destination: "/prisma-orm/create-prisma", + permanent: true, + }, { source: "/orm/next/quickstart/:path*", destination: "/prisma-orm/quickstart/:path*", @@ -380,6 +388,18 @@ const config = { { source: "/guides/next", destination: "/guides", permanent: true }, { source: "/guides/next/:path*", destination: "/guides/:path*", permanent: true }, { source: "/llms/next.txt", destination: "/llms/orm.txt", permanent: true }, + // The CLI engine composes structured-error docsUrls as + // / (path form); the pages anchor codes as #. + { + source: "/cli/error-reference/:code", + destination: "/cli/error-reference#:code", + permanent: false, + }, + { + source: "/orm/reference/error-reference/:code", + destination: "/orm/reference/error-reference#:code", + permanent: false, + }, { source: "/prisma-postgres/quickstart/prisma-next", destination: "/prisma-postgres/quickstart/prisma-orm", diff --git a/apps/docs/scripts/generate-error-reference.mjs b/apps/docs/scripts/generate-error-reference.mjs index c74eccf9c0..ee62c2c59f 100644 --- a/apps/docs/scripts/generate-error-reference.mjs +++ b/apps/docs/scripts/generate-error-reference.mjs @@ -1,41 +1,133 @@ -// Generates content/docs/orm/reference/error-reference.mdx from the -// canonical docs/reference/error-reference.md in prisma/prisma (main branch). +// Generates a hosted error-reference page from a canonical +// docs/reference/error-reference.md in a product repo (main branch). // // Usage: -// node scripts/generate-error-reference.mjs [--source ] +// node scripts/generate-error-reference.mjs [--target orm|cli] [--source ] +// +// Targets: +// orm (default) prisma/prisma -> content/docs/orm/reference/error-reference.mdx +// cli prisma/prisma-cli -> content/docs/cli/error-reference.mdx // // Without --source, the file is fetched from raw.githubusercontent.com. // -// Every Prisma 8 error carries a docsUrl of the form -// https://docs.prisma.io/docs/orm/reference/error-reference# -// (builds that predate the Prisma 8 promotion emit /orm/next/... or -// /orm/v8/..., which 308-redirect here with the fragment preserved), so each `### NAMESPACE.SUBCODE` heading -// gets an explicit anchor equal to the raw code text (uppercase, with the dot) -// via Fumadocs' `[#custom-id]` syntax. +// Every structured error carries (or can carry) a docsUrl pointing at its +// code's entry on the hosted page — either as a fragment +// (https://docs.prisma.io/docs/orm/reference/error-reference#) or as a +// path segment (…/error-reference/, the shape the CLI engine composes +// from a family docsBaseUrl; next.config.mjs redirects it to the fragment). +// Each `### NAMESPACE.SUBCODE` heading therefore gets an explicit anchor +// equal to the raw code text (uppercase, with the dot) via Fumadocs' +// `[#custom-id]` syntax. import { readFileSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; -const SOURCE_URL = - "https://raw.githubusercontent.com/prisma/prisma/main/docs/reference/error-reference.md"; -const GITHUB_BLOB_BASE = "https://github.com/prisma/prisma/blob/main/docs/reference/"; -const OUTPUT = join( - dirname(fileURLToPath(import.meta.url)), - "../content/docs/orm/reference/error-reference.mdx", -); +const HERE = dirname(fileURLToPath(import.meta.url)); const CODE_HEADING = /^### ([A-Z0-9_]+\.[A-Z0-9_.]+)$/; -async function loadSource() { - const flagIndex = process.argv.indexOf("--source"); - if (flagIndex !== -1) { - const path = process.argv[flagIndex + 1]; - if (!path) throw new Error("--source requires a path"); - return readFileSync(path, "utf8"); +// The canonical ORM source still uses the product's internal conventions. +// Until upstream adopts the published names, rewrite them to the site +// standard: the working name "Prisma Next" is now "Prisma 8" (ADR 242 +// rebrand), and app developers import from a facade package, not the +// unpublished @internal scope. Each rule is a narrow literal so it no-ops +// once upstream catches up. +function applyOrmNamingStandard(body) { + return ( + body + .replace(/Prisma Next\b/g, "Prisma 8") + .replace( + /`@internal\/utils\/structured-error`/g, + "your facade package's `utils/structured-error` subpath (for example `@prisma/orm-postgres/utils/structured-error`)", + ) + // The facade clients by their published names. Backtick-bounded so the + // internal-only testkits (`@internal/postgres-codec-testkit`, ...) keep + // their real names. + .replace(/`@internal\/postgres`/g, "`@prisma/orm-postgres`") + .replace(/`@internal\/sqlite`/g, "`@prisma/orm-sqlite`") + .replace(/`@internal\/mongo`/g, "`@prisma/orm-mongo`") + ); +} + +// Every span this file must treat as opaque, in the forms CommonMark allows: +// a fence opened with three or more backticks or tildes and closed by its own +// delimiter, and an inline span delimited by any number of backticks. Both the +// prose rewriter and the MDX check read this, so neither can reach inside code +// and rewrite an identifier or trip over a brace that is only ever displayed. +const CODE_SEGMENT = /^(`{3,}|~{3,})[^\n]*\n[\s\S]*?^\1[^\S\n]*$|(`+)[^\n]*?\2/gm; + +/** Applies a prose-only rewrite, leaving every code segment untouched. */ +function replaceInProse(body, pattern, replacement) { + let out = ""; + let end = 0; + for (const code of body.matchAll(CODE_SEGMENT)) { + out += body.slice(end, code.index).replace(pattern, replacement) + code[0]; + end = code.index + code[0].length; } - const response = await fetch(SOURCE_URL); + return out + body.slice(end).replace(pattern, replacement); +} + +// prisma-cli names this API after the SDK it calls it through +// (`@prisma/management-api-sdk`), which is right in that repo. The docs site +// publishes the same API as the REST API and does not reintroduce the old +// name in prose (apps/docs/CLAUDE.md). Identifiers keep their real names, so +// this rewrites prose only. +function applyCliNamingStandard(body) { + return replaceInProse(body, /\bManagement API\b/g, "REST API"); +} + +const TARGETS = { + orm: { + sourceRepo: "prisma/prisma", + output: join(HERE, "../content/docs/orm/reference/error-reference.mdx"), + applyNamingStandard: applyOrmNamingStandard, + hostedIntro: + "Each code anchors as `#` — the exact fragment every emitted error carries in its " + + "`docsUrl`. This page is generated from the canonical reference in the `prisma/prisma` " + + "repository, whose CI requires every code in production source to be documented before it ships.", + frontmatter: `--- +title: Error reference +description: Every structured error code Prisma 8 can emit, by namespace, with the condition that raises it. +url: /orm/reference/error-reference +metaTitle: Prisma 8 error reference +metaDescription: Every structured error code Prisma 8 can emit, by namespace, with the condition that raises it. +--- +`, + }, + cli: { + sourceRepo: "prisma/prisma-cli", + output: join(HERE, "../content/docs/cli/error-reference.mdx"), + applyNamingStandard: applyCliNamingStandard, + hostedIntro: + "Each code anchors as `#` — the fragment an emitted error's `docsUrl` resolves to. " + + "This page is generated from the canonical registry in the `prisma/prisma-cli` repository, " + + "whose CI requires every code in production source to be documented before it ships.", + frontmatter: `--- +title: Error reference +description: Every structured error code the unified Prisma CLI can emit, by namespace, with the condition that raises it. +url: /cli/error-reference +metaTitle: Error reference | Prisma 8 CLI +metaDescription: Every structured error code the unified Prisma CLI can emit, by namespace, with the condition that raises it. +--- +`, + }, +}; + +function readFlag(name) { + const i = process.argv.indexOf(name); + if (i === -1) return undefined; + const value = process.argv[i + 1]; + if (!value) throw new Error(`${name} requires a value`); + return value; +} + +async function loadSource(target) { + const path = readFlag("--source"); + if (path) return readFileSync(path, "utf8"); + const url = `https://raw.githubusercontent.com/${target.sourceRepo}/main/docs/reference/error-reference.md`; + const response = await fetch(url); if (!response.ok) { - throw new Error(`Failed to fetch ${SOURCE_URL}: ${response.status}`); + throw new Error(`Failed to fetch ${url}: ${response.status}`); } return response.text(); } @@ -44,57 +136,34 @@ function assertMdxSafe(markdown) { // The page is plain markdown compiled as MDX. Braces and JSX-like tags // outside code spans/fences would change meaning or break the build, so // refuse them here where the failure is attributable to the source file. - const withoutCode = markdown.replace(/```[\s\S]*?```/g, "").replace(/`[^`\n]*`/g, ""); + const withoutCode = markdown.replace(CODE_SEGMENT, ""); const hostile = withoutCode.match(/[{}]|<[A-Za-z/]/); if (hostile) { throw new Error( `Source contains MDX-unsafe text outside code spans (found ${JSON.stringify(hostile[0])}). ` + - "Escape it in prisma/prisma docs/reference/error-reference.md or teach this generator to handle it.", + "Escape it in the canonical error-reference.md or teach this generator to handle it.", ); } } -// The canonical source still uses the product's internal conventions. Until -// upstream adopts the published names, rewrite them to the site standard: -// the working name "Prisma Next" is now "Prisma 8" (ADR 242 rebrand), and app -// developers import from a facade package, not the unpublished @internal -// scope. Each rule is a narrow literal so it no-ops once upstream catches up. -function applyNamingStandard(body) { - return ( - body - .replace(/Prisma Next\b/g, "Prisma 8") - .replace( - /`@internal\/utils\/structured-error`/g, - "your facade package's `utils/structured-error` subpath (for example `@prisma/orm-postgres/utils/structured-error`)", - ) - // The facade clients by their published names. Backtick-bounded so the - // internal-only testkits (`@internal/postgres-codec-testkit`, ...) keep - // their real names. - .replace(/`@internal\/postgres`/g, "`@prisma/orm-postgres`") - .replace(/`@internal\/sqlite`/g, "`@prisma/orm-sqlite`") - .replace(/`@internal\/mongo`/g, "`@prisma/orm-mongo`") - ); -} - -function transform(markdown) { +function transform(target, markdown) { assertMdxSafe(markdown); let body = markdown.replace(/^# Error reference\s*\n/, ""); - body = applyNamingStandard(body); + body = target.applyNamingStandard(body); - // The source intro describes itself from the prisma/prisma repo's point of - // view ("canonical source", its own CI check). Reworded for readers of the + // The source intro describes itself from the product repo's point of view + // ("canonical source", its own CI check). Reworded for readers of the // hosted page; if upstream rewrites the sentence the original is kept. body = body.replace( /It is the canonical source for the hosted reference at[\s\S]*?missing from this page\./, - "Each code anchors as `#` — the exact fragment every emitted error carries in its " + - "`docsUrl`. This page is generated from the canonical reference in the `prisma/prisma` " + - "repository, whose CI requires every code in production source to be documented before it ships.", + target.hostedIntro, ); - // Repo-relative links point at files that only exist in prisma/prisma. - body = body.replace(/\]\((\.\.?\/[^)]+)\)/g, (_, target) => { - const url = new URL(target, `${GITHUB_BLOB_BASE}error-reference.md`); + // Repo-relative links point at files that only exist in the source repo. + const blobBase = `https://github.com/${target.sourceRepo}/blob/main/docs/reference/`; + body = body.replace(/\]\((\.\.?\/[^)]+)\)/g, (_, linkTarget) => { + const url = new URL(linkTarget, `${blobBase}error-reference.md`); return `](${url.href})`; }); @@ -119,23 +188,23 @@ function transform(markdown) { throw new Error(`Duplicate error codes in source: ${duplicates.join(", ")}`); } - const frontmatter = `--- -title: Error reference -description: Every structured error code Prisma 8 can emit, by namespace, with the condition that raises it. -url: /orm/reference/error-reference -metaTitle: Prisma 8 error reference -metaDescription: Every structured error code Prisma 8 can emit, by namespace, with the condition that raises it. ---- - + const header = `${target.frontmatter} {/* Generated by scripts/generate-error-reference.mjs from - https://github.com/prisma/prisma/blob/main/docs/reference/error-reference.md + https://github.com/${target.sourceRepo}/blob/main/docs/reference/error-reference.md Do not edit by hand — changes are overwritten by the sync workflow. */} `; - return { mdx: frontmatter + body, codeCount: codes.length }; + return { mdx: header + body, codeCount: codes.length }; } -const { mdx, codeCount } = transform(await loadSource()); -writeFileSync(OUTPUT, mdx); -console.log(`Wrote ${OUTPUT} with ${codeCount} error codes.`); +const targetName = readFlag("--target") ?? "orm"; +const target = TARGETS[targetName]; +if (!target) { + throw new Error( + `Unknown --target ${JSON.stringify(targetName)}. Known: ${Object.keys(TARGETS).join(", ")}`, + ); +} +const { mdx, codeCount } = transform(target, await loadSource(target)); +writeFileSync(target.output, mdx); +console.log(`Wrote ${target.output} with ${codeCount} error codes.`);