DEV Community

umzzil nng
umzzil nng

Posted on Originally published at oraerror.com

PostgreSQL 39P02 Error: Causes and Solutions Complete Guide

PostgreSQL Error 39P02: srf protocol violated

The 39P02: srf protocol violated error occurs when a Set-Returning Function (SRF) — a function designed to return multiple rows — fails to follow PostgreSQL's internal protocol for producing result sets. This typically happens in C-language extensions, procedural language functions using RETURNS SETOF, or after major version upgrades when extensions are not recompiled against the new PostgreSQL binaries.


Top 3 Causes and Fixes

1. Incorrect C-Language SRF Implementation

C-based SRFs must use the SRF_IS_FIRSTCALL(), SRF_FIRSTCALL_INIT(), SRF_PERCALL_SETUP(), SRF_RETURN_NEXT(), and SRF_RETURN_DONE() macros in the correct order. Skipping any of these — especially forgetting SRF_RETURN_DONE() — triggers the protocol violation.

Diagnosis and Quick Fix:

-- Check all C-language set-returning functions in your database
SELECT
    n.nspname  AS schema,
    p.proname  AS function_name,
    p.probin   AS shared_library
FROM pg_proc p
JOIN pg_namespace n ON p.pronamespace = n.oid
JOIN pg_language l  ON p.prolang = l.oid
WHERE p.proretset = true
  AND l.lanname = 'c'
  AND n.nspname NOT IN ('pg_catalog', 'information_schema');

-- Drop and recreate the broken function after fixing the C code
DROP FUNCTION IF EXISTS broken_srf_function();

CREATE OR REPLACE FUNCTION broken_srf_function()
RETURNS SETOF TEXT
AS '/path/to/fixed_extension.so', 'broken_srf_function'
LANGUAGE C STRICT;
Enter fullscreen mode Exit fullscreen mode

2. Extension Incompatibility After Major Version Upgrade

After upgrading PostgreSQL (e.g., v14 → v15), C extensions compiled against the old version can violate the SRF protocol due to ABI changes. Always recompile or reinstall extensions against the new PostgreSQL version.

-- Check installed extension versions
SELECT name, default_version, installed_version
FROM pg_available_extensions
WHERE installed_version IS NOT NULL
ORDER BY name;

-- Attempt to update the extension in-place
ALTER EXTENSION your_extension_name UPDATE;

-- If update is not possible, reinstall
DROP EXTENSION IF EXISTS your_extension_name CASCADE;
-- (Install the correct OS package version first, then:)
CREATE EXTENSION your_extension_name;

-- Confirm server version to match against extension build
SELECT version();
Enter fullscreen mode Exit fullscreen mode

3. Incorrect RETURNS SETOF in PL/pgSQL Functions

Using RETURN value instead of RETURN NEXT value inside a RETURNS SETOF function, or failing to call a final RETURN to signal completion, can trigger this error.

-- BAD: incorrect pattern
CREATE OR REPLACE FUNCTION bad_example()
RETURNS SETOF INTEGER
LANGUAGE plpgsql AS $$
BEGIN
    RETURN 1; -- Wrong! This does not follow SRF protocol
END;
$$;

-- GOOD: correct use of RETURN NEXT
CREATE OR REPLACE FUNCTION good_example_v1()
RETURNS SETOF INTEGER
LANGUAGE plpgsql AS $$
DECLARE
    i INTEGER;
BEGIN
    FOR i IN 1..5 LOOP
        RETURN NEXT i;
    END LOOP;
    RETURN; -- explicit termination
END;
$$;

-- GOOD: correct use of RETURN QUERY
CREATE OR REPLACE FUNCTION good_example_v2(p_schema TEXT)
RETURNS SETOF TEXT
LANGUAGE plpgsql AS $$
BEGIN
    RETURN QUERY
        SELECT tablename::TEXT
        FROM pg_tables
        WHERE schemaname = p_schema;
END;
$$;

-- GOOD: RETURNS TABLE pattern
CREATE OR REPLACE FUNCTION good_example_v3()
RETURNS TABLE(id INT, label TEXT)
LANGUAGE plpgsql AS $$
BEGIN
    id := 1; label := 'first';  RETURN NEXT;
    id := 2; label := 'second'; RETURN NEXT;
END;
$$;

-- Test the functions
SELECT * FROM good_example_v1();
SELECT * FROM good_example_v2('public');
SELECT * FROM good_example_v3();
Enter fullscreen mode Exit fullscreen mode

Quick Prevention Tips

Always validate extensions before upgrading PostgreSQL.
Run pg_upgrade --check before any major version upgrade, and ensure all third-party extensions (PostGIS, TimescaleDB, etc.) have a version available for the target PostgreSQL release. Include SRF function regression tests in your CI/CD pipeline.

Prefer PL/pgSQL over C for custom SRFs when possible.
C-based SRFs are powerful but error-prone. If performance allows, implement SRFs in PL/pgSQL using RETURN NEXT or RETURN QUERY, which are far less likely to produce protocol violations. When C is necessary, strictly follow the SRF macro pattern and add unit tests that call the function in isolation.


Related Errors

  • 39P01invalid_transaction_termination: improper transaction control inside a function context.
  • 42P13invalid_function_definition: malformed function definition, often a root cause of SRF issues.
  • XX000internal_error: may appear alongside 39P02 in server logs when a C extension crashes.

📖 Want a more detailed guide?
Check out the full in-depth version (Korean) on oraerror.com — includes detailed analysis, additional SQL examples, and prevention tips.

Top comments (0)