PostgreSQL throws this runtime error when a function, trigger, or DO block executes a SQL command that is disallowed in that context.
PostgreSQL Error 38003 (prohibited_sql_statement_attempted) occurs when a function, trigger, or DO block issues a SQL command that the server forbids, such as COMMIT or DDL. Remove or move the prohibited statement outside the routine, or convert the logic to a stored procedure to resolve the error.
PostgreSQL Error 38003
PostgreSQL raises error 38003 when a function, trigger or DO block executes a SQL command that the server forbids in that context. Typical offenders are transaction control statements like COMMIT, ROLLBACK, and SAVEPOINT, as well as certain DDL or CALL statements inside SQL-language functions.
The runtime blocks these statements to protect transactional consistency. The server aborts the offending command and returns SQLSTATE 38003 with the message "prohibited SQL statement attempted".
Clearing the error is critical because the routine will not finish and any following code will not run.
Error 38003 appears when the routine’s execution environment is classified as SQL-invoked and attempts a prohibited statement.
PostgreSQL forbids transaction control, large schema changes, VACUUM, LISTEN, UNLISTEN, and certain role-changing commands inside functions, triggers, and procedural blocks.
The error also arises if SECURITY DEFINER functions issue disallowed statements without configuring SET parameters, or when an extension generates an implicit COMMIT inside a function.
Replace the illegal command with an allowed alternative. Move COMMIT or ROLLBACK outside the function and let PostgreSQL handle atomicity automatically.
For DDL, execute it before or after the routine instead of inside.
If the logic truly needs multiple transactions, convert the function to a stored procedure and call it with CALL, because procedures can run BEGIN and COMMIT legally.
COMMIT inside plpgsql function - remove COMMIT, wrap the function call in a client-side transaction.
CREATE TABLE in trigger - pre-create the table or run CREATE TABLE IF NOT EXISTS outside the trigger.
VACUUM invoked in SECURITY DEFINER function - schedule VACUUM through cron, pg_cron, or an administrative procedure instead of calling it inside the function.
Keep functions side-effect-free and restrict them to data-manipulation statements (SELECT, INSERT, UPDATE, DELETE).
Reserve transaction control and heavy maintenance commands for stored procedures or client scripts.
Using the Galaxy SQL editor, lint routines with the built-in checker or AI copilot. Galaxy flags disallowed statements before you run them, preventing 38003 from hitting production.
SQLSTATE 25001 – active SQL transaction happens when BEGIN is issued inside a function. Remove the transaction block.
SQLSTATE 0A000 – feature not supported appears for unsupported commands in routines, such as LISTEN/UNLISTEN.
Refactor the logic or move it to a stored procedure.
.
Issuing BEGIN, COMMIT, ROLLBACK, or SAVEPOINT within SQL or PL/pgSQL functions immediately triggers error 38003.
CREATE, ALTER, DROP, TRUNCATE, or VACUUM statements are prohibited in functions and will raise the error.
VACUUM, ANALYZE, CLUSTER, and REINDEX run with elevated rights and are blocked inside functions.
SET ROLE, RESET ROLE, and SET SESSION AUTHORIZATION are disallowed inside routines and cause the error.
.
No. PostgreSQL blocks all transaction control inside functions. Convert the logic to a stored procedure and call it with CALL.
All languages obey the prohibition. SQL, PL/pgSQL, PL/Python, etc. will raise 38003 for disallowed statements.
Security context does not matter. The server enforces the rule for consistency. SECURITY DEFINER functions still raise 38003.
Galaxy’s static analysis warns about transaction or DDL statements inside functions and suggests moving them before execution.