39P01ERRORTier 2 — Caution✅ HIGH confidencetrigger protocol violated
What this means
SQLSTATE 39P01 is a Postgres-specific error raised when a trigger function violates the trigger calling protocol — for example, returning an incompatible value from a row-level trigger (must return a RECORD or NULL for row triggers).
Why it happens
- 1A row-level trigger function returns a value of the wrong type instead of the modified row or NULL
- 2A trigger function returns a non-RECORD value from a BEFORE row trigger
- 3PL/C or external language trigger function does not comply with the Postgres trigger calling conventions
How to reproduce
Trigger function returning wrong type.
CREATE OR REPLACE FUNCTION bad_trigger() RETURNS TRIGGER AS $
BEGIN
RETURN 42; -- should return NEW, OLD, or NULL
END;
$ LANGUAGE plpgsql;Fix 1: Return NEW (or OLD) from BEFORE row triggers
When writing PL/pgSQL trigger functions.
CREATE OR REPLACE FUNCTION good_trigger() RETURNS TRIGGER AS $
BEGIN
-- modify NEW as needed
RETURN NEW; -- required for BEFORE triggers
END;
$ LANGUAGE plpgsql;Why this works
BEFORE row triggers must return the row to be inserted/updated (NEW), the original row (OLD), or NULL to cancel the operation. Any other return type violates the protocol.
Sources
📚 Official docs: https://www.postgresql.org/docs/current/errcodes-appendix.html
📚 Feature docs: https://www.postgresql.org/docs/current/plpgsql-trigger.html
🔧 Source ref: Class 39 — External Routine Invocation Exception (Postgres-specific)
Confidence assessment
✅ HIGH confidence
Postgres-specific. Stable across all versions. The trigger return convention is well-documented.
See also
🔗 Related errors
📄 Reference pages