Common SQL Errors

PostgreSQL 2F002 modifying_sql_data_not_permitted

August 4, 2025

SQLSTATE 2F002 appears when a statement tries to change data in a READ ONLY context such as a function or transaction block declared as read only.

Sign up for the latest in common SQL errors from the Galaxy Team!
Welcome to the Galaxy, Guardian!
You'll be receiving a confirmation email

Follow us on twitter :)
Oops! Something went wrong while submitting the form.

What is modifying_sql_data_not_permitted in PostgreSQL?

PostgreSQL Error 2F002 (modifying_sql_data_not_permitted) occurs when an INSERT, UPDATE, DELETE, or TRUNCATE runs inside a read-only function or transaction. Convert the function or block to VOLATILE/MODIFIES SQL DATA or remove the read-only setting to resolve the issue.

Error Highlights

Typical Error Message

PostgreSQL Error 2F002

Error Type

Permission Error

Language

PostgreSQL

Symbol

modifying_sql_data_not_permitted

Error Code

2F002

SQL State

Explanation

Table of Contents

What is modifying_sql_data_not_permitted in PostgreSQL?

PostgreSQL raises the condition modifying_sql_data_not_permitted (SQLSTATE 2F002) when an SQL command that changes data executes inside a context that forbids data modification.

The error protects database integrity by ensuring that functions, procedures, or transactions declared as READ ONLY do not perform INSERT, UPDATE, DELETE, or TRUNCATE operations.

What Causes This Error?

The server checks the volatility and access mode of the surrounding block.

If it is declared STRICTLY READ ONLY, any statement that touches rows violates the contract and triggers 2F002.

Typical offenders are write statements inside IMMUTABLE or STABLE functions, read-only transaction blocks started with START TRANSACTION READ ONLY, or pglogical replication apply workers.

How to Fix PostgreSQL Error 2F002

Identify the object or transaction that enforces read-only mode.

Change its declaration to VOLATILE or MODIFIES SQL DATA, or remove the READ ONLY clause, then rerun the write statement.

When modifying production code, favour minimal scope: wrap only the required write in a separate VOLATILE helper function or commit and reopen a read-write transaction.

Common Scenarios and Solutions

Write inside function: redeclare the function as VOLATILE or add the CALLED ON NULL INPUT property to allow modification.

Write inside BEGIN READ ONLY: end the transaction, start a new read-write transaction, and execute the DML.

Best Practices to Avoid This Error

Always match function volatility to its behaviour.

Use IMMUTABLE/STABLE for pure reads only. Version control function code in Galaxy Collections to catch accidental writes during code review.

During long analytical sessions, start transactions without READ ONLY unless absolutely necessary, or open a second session for DML.

Related Errors and Solutions

SQLSTATE 25006 (read_only_sql_transaction) fires when writes run in SERIALIZABLE READ ONLY DEFERRABLE mode. SQLSTATE 2F003 (prohibited_sql_statement_attempted) appears when you run transaction commands inside a function declared SECURITY DEFINER.

.

Common Causes

Function declared IMMUTABLE or STABLE but contains INSERT/UPDATE

PostgreSQL forbids data changes in IMMUTABLE or STABLE functions.

Any DML inside triggers SQLSTATE 2F002.

Transaction started with START TRANSACTION READ ONLY

A manual or driver-initiated read-only transaction blocks all data-changing statements until commit or rollback.

SET default_transaction_read_only = on at session level

Some connection pools enforce global read-only mode, leading unsuspecting code to trigger the error.

Logical replication apply worker

Apply workers run in read-only mode for safety; user DML inside their callbacks will fail with 2F002.

.

Related Errors

FAQs

Can I keep a function STABLE and still log data?

No. Any data-changing operation invalidates STABLE semantics. Split the logic: one STABLE function for reads and a separate VOLATILE function for logging.

Does SET ROLE cause this error?

SET ROLE alone does not, but the new role may have default_transaction_read_only = on, indirectly triggering 2F002 when you attempt DML.

Will changing the function to VOLATILE affect performance?

VOLATILE disables certain planner optimizations. For infrequent calls, the impact is negligible. Benchmark critical paths before and after the change.

How does Galaxy help avoid 2F002?

Galaxy’s AI copilot flags DML inside read-only contexts during query review, while version-controlled Collections ensure vetted function definitions stay consistent.

Start Querying with the Modern SQL Editor Today!
Welcome to the Galaxy, Guardian!
You'll be receiving a confirmation email

Follow us on twitter :)
Oops! Something went wrong while submitting the form.

Check out some other errors

Trusted by top engineers on high-velocity teams
Aryeo Logo
Assort Health
Curri
Rubie Logo
Bauhealth Logo
Truvideo Logo