# 25P01 — no_active_sql_transaction

> PostgreSQL SQLSTATE 25P01: operations such as SAVEPOINT require an explicit transaction block.
---

# 25P01 — no_active_sql_transaction

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

`25P01` reports that an operation needs an active SQL transaction. The selected case sends `SAVEPOINT` with autocommit enabled, receives the exact error while the session remains `IDLE`, then repeats the operation inside `BEGIN` and commits.

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

| Field | Value |
| --- | --- |
| SQLSTATE | `25P01` |
| Condition | `no_active_sql_transaction` |
| Status | `active` |
| Known present by | `7.4` |
| 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_NO_ACTIVE_SQL_TRANSACTION` |
| Aliases | `—` |

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

## Meaning {#meaning}

The source formats the statement name into `%s can only be used in transaction blocks`; the selected `SAVEPOINT` path is an `ERROR`. The same SQLSTATE also has `COMMIT AND CHAIN`/`ROLLBACK AND CHAIN` errors and no-transaction `COMMIT`/`ROLLBACK` warnings with the fixed text `there is no transaction in progress`.

## Diagnosis {#diagnosis}

Check whether the client is in an explicit block before issuing SAVEPOINT, RELEASE SAVEPOINT, or ROLLBACK TO SAVEPOINT. In the selected run, the failed autocommit statement leaves `IDLE`; the repair uses `BEGIN`, `SAVEPOINT`, `RELEASE`, and `COMMIT`.

## Response {#response}

Start an explicit transaction before creating a savepoint. If the operation was sent without a block, correct the client transaction wrapper and retry the intended operation; no rollback is needed for this autocommit error because no open failed block remains.

## Source message {#messages}

`xact.c` formats `%s can only be used in transaction blocks`; this case substitutes `SAVEPOINT` with `ERROR`. `COMMIT AND CHAIN` and `ROLLBACK AND CHAIN` use the same dynamic form when no block exists, while no-transaction `COMMIT`/`ROLLBACK` use the `WARNING` text `there is no transaction in progress`.

## Observed diagnostics {#observed}

`18.6 (Homebrew) / latest`: SQLSTATE `25P01`; primary `SAVEPOINT can only be used in transaction blocks`; after-error `IDLE`; explicit repair `INTRANS → IDLE`.
`10.21 (Debian 10.21-1.pgdg90+1) / pg10`: SQLSTATE `25P01`; primary `SAVEPOINT can only be used in transaction blocks`; after-error `IDLE`; explicit repair `INTRANS → IDLE`.

## Representative case {#case}

The runner reads the no-block SAVEPOINT and explicit-block repair statements below from the shared registry; complete assertions, environment, and cleanup are in [case export](../data/cases/25p01.json).

<!-- BEGIN SQLSTATE SNIPPET: no_active_sql_transaction -->
```sql
-- trigger
SAVEPOINT outside_block;
-- begin
BEGIN;
-- savepoint
SAVEPOINT inside_block;
-- release
RELEASE SAVEPOINT inside_block;
-- commit
COMMIT;
-- verify
SELECT 1;
```
<!-- END SQLSTATE SNIPPET -->

The SQLSTATE, diagnostics, states, and repair assertions for this excerpt come from the shared registry (SHA-256 `a1ffffc778f82789f1c1ac4027a109fc76e4b315ef2e3a5bdbfc47c8f84ce951`); [structured evidence](../data/evidence/25p01.json).

Authored evidence IDs: `identity`, `savepoint-path`, `runtime`. Selected runtime records: `runtime.25P01-batch2-latest-20260909.latest`, `runtime.25P01-batch2-pg10-20260909.pg10`.
## Versions and limits {#versions}

The SAVEPOINT case returns 25P01 with the same primary text on 18.6 and 10.21, and the explicit-block repair finishes `IDLE` on both.

## Related {#related}

[25005 branch transaction no active SQL transaction](../25005/), [25P02 failed SQL transaction](../25p02/), [25006 read-only SQL transaction](../25006/).

## Sources {#sources}

- [`src.errcodes.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt) (SHA-256 `6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba`)
- `src.calls.REL_18_6` — `raw/calls/REL_18_6.jsonl` (SHA-256 `9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf`)
- [`src.xact.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/access/transam/xact.c#L3724-L3749) (SHA-256 `75b012c0b047d1dc905a30975c244beec366e45eac0dbf109fd21bcd611a8e39`)
- [`doc.savepoint.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/doc/src/sgml/ref/savepoint.sgml#L68-L78) (SHA-256 `aa6e167d373da6118249c87404a7b2ff8be8c7df790449814f1d9dc433bbd428`) · [official documentation](https://www.postgresql.org/docs/18/sql-savepoint.html)
- [`src.xact.savepoint.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/access/transam/xact.c#L4418-L4424) (SHA-256 `75b012c0b047d1dc905a30975c244beec366e45eac0dbf109fd21bcd611a8e39`)
