# 2F002 — modifying_sql_data_not_permitted

> Source-bounded reference for PostgreSQL SQLSTATE 2F002.
---

# 2F002

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

SQLSTATE 2F002 names the standard SQL Routine Exception member for modifying SQL data when the routine’s declared data-access contract does not permit it. The locked PostgreSQL 18.6 definition contains the member, but its resolved core/contrib call scan has no native report group. Do not infer that PostgreSQL `VOLATILE`, `STABLE`, or `IMMUTABLE` alone maps to this SQLSTATE.

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

| Field | Value |
| --- | --- |
| SQLSTATE | `2F002` |
| Condition | `modifying_sql_data_not_permitted` |
| 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_S_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED` |
| Aliases | `—` |

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

## Meaning {#meaning}

The condition is about a routine data-access restriction in an implementation that enforces that contract. The PostgreSQL catalogue row supplies identity and the macro; it does not establish a backend enforcement path or a particular routine language. An extension, embedded-SQL implementation, driver, or remote server may use the standard member independently.

## Messages {#messages}

No fixed PostgreSQL message variant was adopted for this condition because the bounded scan did not resolve a native emitting call.

## Diagnosis {#diagnosis}

First preserve the actual SQLSTATE and inspect the routine declaration and the owner that enforced it. Determine whether the attempted statement modified data, whether the routine was declared with a restrictive data-access characteristic, and whether the code came from a remote or client implementation. If the server returned another code, follow that code rather than treating 2F002 as a synonym for a PostgreSQL function volatility error.

## Response {#response}

Change the routine’s data-access declaration only when the producing implementation documents that as the supported repair, or move the data-modifying work to an allowed routine boundary. Otherwise correct the caller or remote contract. Do not add a generic retry: a rejected data change did not by itself establish whether surrounding work was committed.

## Versions {#versions}

The locked catalogue places this condition at least by PostgreSQL 7.4. The release definitions cover the published snapshots listed in the facts block; source-path status is limited to the fixed PostgreSQL 18.6 context cited below.

## Related {#related}

[`2F000`](../2f000/), [`0A000`](../0a000/)

## Sources {#sources}

The fixed [errcodes definition](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt#L290) establishes the member and macro; the [SQLSTATE appendix](https://www.postgresql.org/docs/18/errcodes-appendix.html) identifies the standard condition. The locked core/contrib scan found no resolved native 2F002 report group. See the structured [evidence record](../data/evidence/2f002.json) for fixed source paths, scan scope, and unresolved runtime boundaries.
