# P0001 — raise_exception

> PostgreSQL uses SQLSTATE P0001 for a PL/pgSQL RAISE EXCEPTION with no explicit condition or SQLSTATE. Diagnose the application control flow and recover at the correct transaction boundary.
---

## At a glance {#at-a-glance}

`P0001` is the `raise_exception` condition in PostgreSQL's PL/pgSQL-specific Class P0. A `RAISE EXCEPTION` statement with no condition name and no explicit SQLSTATE defaults to this code. The message is supplied by the function author, so `P0001` is usually an application or procedure control signal rather than a diagnosis of one server subsystem.

The level and code are separate choices. `EXCEPTION` is the default `RAISE` level and normally aborts the current transaction. `NOTICE`, `WARNING`, `INFO`, `LOG`, and `DEBUG` generate messages without that exception behavior; an explicit `ERRCODE` can also choose a different SQLSTATE. Always capture the severity and SQLSTATE together.

The representative case `plpgsql_raise_exception` creates a function containing `RAISE EXCEPTION 'calibration exception'`, calls it, and then runs `SELECT 1` on the same autocommit connection. PostgreSQL 18.6 and 10.21 both returned `P0001`, preserved the message, left the connection `IDLE`, and accepted the follow-up query. The SQL excerpt below is the complete ordered function, call, and follow-up from the shared snippet registry; the runner owns the schema-qualified name and cleanup.

<!-- BEGIN SQLSTATE FACTS: generated by scripts/generate.py; do not edit -->

| Field | Value |
| --- | --- |
| SQLSTATE | `P0001` |
| Condition | `raise_exception` |
| Status | `active` |
| Known present by | `8.0.0` |
| Locked snapshots | `9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3` |
| Macros | `ERRCODE_RAISE_EXCEPTION` |
| Aliases | `—` |

<!-- source facts: data/errcodes/P0001.json -->
<!-- END SQLSTATE FACTS -->

## Meaning and trigger paths {#meaning}

The 18.6 directory places `P0001` in Class P0, `PL/pgSQL Error`, and names it `raise_exception`. The class is PostgreSQL-specific. In the PL/pgSQL executor, the default code is assigned only when no code was supplied and the level is at least `ERROR`; the executor then reports the caller's message and optional detail, hint, and object fields.

The syntax supports several distinct paths:

- `RAISE EXCEPTION 'message'` uses `P0001` by default.
- `RAISE EXCEPTION condition_name` uses the condition's SQLSTATE, so it need not be `P0001`.
- `RAISE EXCEPTION SQLSTATE '5-character-code'` or `RAISE ... USING ERRCODE = ...` lets a procedure expose a domain-specific contract. PostgreSQL permits user-chosen five-character codes other than `00000`.
- A lower level such as `RAISE WARNING 'message'` emits a message at that priority. It is not the same transaction event as `RAISE EXCEPTION`, even if the caller chooses an explicit error code.

The no-argument `RAISE;` form is re-raise control inside an active exception handler. Its behavior and SQLSTATE are determined by the exception being re-raised; it is not a new default `P0001` event.

## Messages and diagnostics {#messages}

The representative registry operation is:

<!-- BEGIN SQLSTATE SNIPPET: plpgsql_raise_exception -->
```sql
CREATE FUNCTION raise_exception_case() RETURNS void
LANGUAGE plpgsql AS $$
BEGIN
    RAISE EXCEPTION 'calibration exception';
END
$$;
SELECT raise_exception_case();
SELECT 1;
```
<!-- END SQLSTATE SNIPPET -->

The function name is schema-qualified and generated by the test executor in the actual run. The observed 18.6 diagnostic was:

```text
SQLSTATE: P0001
severity: ERROR
message_primary: calibration exception
context: PL/pgSQL function ...raise_exception_case() line 3 at RAISE
source: pl_exec.c / exec_stmt_raise / line 3923
```

There is no universal English primary message for `P0001`; the function supplies it. `USING MESSAGE`, `DETAIL`, `HINT`, `COLUMN`, `CONSTRAINT`, `DATATYPE`, `TABLE`, and `SCHEMA` can add structured diagnostics. Localized message text can change while SQLSTATE remains stable, so branch on `P0001` and inspect the structured fields rather than parsing the primary string.

## Diagnosis {#diagnosis}

First determine whether the code came from an intentional `RAISE EXCEPTION` or from a different domain condition that the function explicitly selected. Record SQLSTATE, localized and nonlocalized severity, primary message, detail, hint, context, source location, and the statement that called the function. In a PL/pgSQL handler, `SQLSTATE` and `SQLERRM` identify the active exception, while `GET STACKED DIAGNOSTICS` retrieves its fields.

Then locate the function branch and its transaction context. A failed call in autocommit ends that statement and leaves the connection ready for another command, as the representative case shows. A call inside an explicit transaction normally leaves the transaction aborted until the client issues `ROLLBACK` or rolls back to a savepoint. The server connection is not necessarily terminated.

An `EXCEPTION` clause changes the boundary. The protected body runs in a subtransaction; when it errors, persistent changes made by that body are rolled back before the first matching condition handler runs, while changes made outside it remain. `WHEN OTHERS` matches every error except `QUERY_CANCELED` and `ASSERT_FAILURE`; it is broad and should not be used as a substitute for identifying the intended `P0001` path.

## Response {#response}

Use `P0001` when the procedure intentionally exposes the generic PL/pgSQL raise contract. If callers need to distinguish validation, conflict, quota, or another business outcome, choose and document an appropriate SQLSTATE and add `DETAIL` or `HINT` that helps the caller act. Do not turn unrelated server errors into `P0001` merely to simplify application code.

At the client boundary, roll back an explicit transaction before issuing unrelated commands, or use a savepoint when the caller can safely isolate the function call. In PL/pgSQL, prefer a narrow handler such as `WHEN raise_exception` or `WHEN SQLSTATE 'P0001'` when the recovery is specific. If a broad handler is required, preserve `RETURNED_SQLSTATE`, `MESSAGE_TEXT`, `PG_EXCEPTION_DETAIL`, `PG_EXCEPTION_HINT`, and context before deciding whether to continue or re-raise.

The natural `RAISE EXCEPTION` case is safe to demonstrate because it exercises the intended PL/pgSQL mechanism. That does not make `P0001` evidence of a server fault; it is an explicit exception raised by the function.

## Versions {#versions}

The catalogue records `P0001` in the locked 8.0.0–8.4.22 pre-9.0 formal sources, every formal snapshot from 9.0.23 through 18.6, and the 19 Beta 3 preview. The same-tag `REL8_1_4` `errcodes.sgml` table already lists `P0001` as `raise_exception`, confirming that condition-name observation by 8.1.4. The class title is `PL/pgSQL Error (PostgreSQL-specific error class)` in the 9.0 header view and changes to `PL/pgSQL Error` in the 9.1 text definition. Candidate source gaps remain for 7.0–7.3; these are observed catalogue boundaries, not asserted implementation introduction dates.

The fixed 18.6 source commit is `724edf9bde9d356724ad384a2e196edc3c9f80f7`. The default `RAISE EXCEPTION` rule is documented for PostgreSQL 18 and source-confirmed in the 18.6 executor. The representative case passed on PostgreSQL 18.6 and 10.21; it does not test every custom code, handler, or transaction mode.

## Related {#related}

[`P0000` — `plpgsql_error`](../p0000/) is the broader PL/pgSQL-specific class condition. [`P0002` — `no_data_found`](../p0002/), [`P0003` — `too_many_rows`](../p0003/), and [`P0004` — `assert_failure`](../p0004/) are distinct P0 conditions. [`25P02` — `in_failed_sql_transaction`](../25p02/) describes the follow-on state after an unhandled exception aborts an explicit transaction. [`XX000` — `internal_error`](../xx000/) is a server internal-error code and should not be used as a synonym for an intentional `RAISE`.

## Sources {#sources}

The structured evidence is recorded in the [public evidence JSON](../data/evidence/p0001.json). Source records are pinned to PostgreSQL commit `724edf9bde9d356724ad384a2e196edc3c9f80f7`; runtime records retain the shared snippet registry, both target summaries, and run `P0001-snippet-registry-final-20260909`.

- `src.errcodes.18.6` — [`errcodes.txt`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt#L487-L494)
- `src.pl-exec.18.6` — [`pl_exec.c`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/pl/plpgsql/src/pl_exec.c#L3889-L3923)
- `doc.plpgsql.18` — [Errors and Messages](https://www.postgresql.org/docs/18/plpgsql-errors-and-messages.html) and [Error Trapping](https://www.postgresql.org/docs/18/plpgsql-control-structures.html)
- `doc.protocol.18` — [Error and Notice Message Fields](https://www.postgresql.org/docs/18/protocol-error-fields.html)
- `doc.transactions.18` — [Transactions](https://www.postgresql.org/docs/18/tutorial-transactions.html)
