A developer option, and a genuinely useful one. backtrace_functions takes a comma-separated list of internal C function names; if an error is raised inside any function in the list, PostgreSQL writes a C-level stack trace to the server log alongside the error. Added in PostgreSQL 13. Default empty. Context is superuser (or any user with the appropriate SET privilege). Not available on every platform, and the quality of the output depends on how PostgreSQL was compiled.

This is unusual territory for an operator — it is a parameter for inspecting the server’s own source code when something goes wrong, not for tuning behavior. But if you have ever stared at a ERROR: tuple concurrently updated or a cache lookup failed for relation NNNNN and wondered “where in the source code does that come from,” this is the tool.

The workflow

Reproduce the error with verbose output to find the C function name:

1\set VERBOSITY verbose
2SELECT * FROM nonexistent;
3-- ERROR: 42P01: relation "nonexistent" does not exist
4-- LOCATION: parserOpenTable, parse_relation.c:1421

The LOCATION: line gives you the function: parserOpenTable. Set it as the target:

1ALTER SYSTEM SET backtrace_functions = 'parserOpenTable';
2SELECT pg_reload_conf();

Then re-run the failing query. The server log now contains the error and a stack trace:

1ERROR: relation "nonexistent" does not exist at character 15
2BACKTRACE:
3 parserOpenTable + 124
4 addRangeTableEntry + 272
5 transformFromClauseItem + 256
6 transformFromClause + 132
7 transformSelectStmt + 128
8 ...

Suddenly the error has a calling context. You know how the query reached the failing function.

Caveats

Several, all platform-dependent:

  • Debug symbols required. A PostgreSQL binary built without --enable-debug (or its packaging equivalent) produces backtraces with addresses but no function names — useless. Most distributions’ default postgresql package ships with adequate symbols; some don’t. Run a backtrace once to check.
  • Static functions don’t resolve. C static functions aren’t in the dynamic symbol table. PostgreSQL is built without -rdynamic, which means a stack frame inside a static function shows up as an address rather than a name. Use addr2line to recover the name from the address against your binary.
  • Not every platform. macOS works. Linux with glibc works. Various BSDs work. Windows and some minor platforms don’t. The docs list the qualification with their usual restraint.
  • It is a developer option. Like every other parameter under that heading in the docs, it carries the implicit warning: do not point this at random functions on a production server in the hope of insight. Targeted use only.

When to use it

Specific debugging scenarios where you need to understand a server-side error path:

  • Extension development, especially extensions that interact with the executor or planner and produce errors whose origin isn’t obvious from the message alone.
  • Reproducible mystery errors where you want to file a bug report against PostgreSQL itself. Including a stack trace dramatically improves the odds that someone on pgsql-bugs will be able to act on it.
  • Source-code exploration — set the GUC for a function you’re studying, run queries that hit it, and watch the call paths.

The closely-related backtrace_on_internal_error, added more recently, automatically backtraces every elog(ERROR, ...) internal-error message without requiring a function name. That parameter will get its own post next.

Recommendation: Leave empty in production. Reach for it when you have a specific error and a specific function in mind. Verify your binary actually produces symbol-resolved backtraces before relying on it in earnest. If you are debugging an internal error rather than a normal one, the sibling parameter is the better tool.