Article

PostgreSQL’s 100-argument limit: rethink inputs before raising max_function_args

PostgreSQL’s max_function_args is a read-only value, defaulting to 100; changing it requires rebuilding the server and C extensions. Learn why 51 JSON key/value pairs exceed the limit and how rows or arrays can consolidate arguments.

Share

Koharu's reading tip

Distinguish the number of data fields from the number of direct function arguments. Then look for an input shape that preserves your JSON value types.

Koharu's reading tip

Adding fields to a JSON response can unexpectedly trigger a PostgreSQL error about too many function arguments. That is when you may encounter max_function_args, a name that sounds like an invitation to increase a setting.

Christophe Pettus’s “All Your GUCs in a Row: max_function_args” explores the limit and its connection to rebuilding PostgreSQL. For application developers, it raises a practical question: does every data field need to become a separate argument?

A JSON example makes the counting rule clear and leads to alternatives that preserve value types. The supporting documentation and implementation discussed here target PostgreSQL 18.

Why 51 JSON key/value pairs become 102 arguments

jsonb_build_object takes alternating keys and values. Thus, 50 pairs require 50 × 2 = 100 arguments, while 51 require 51 × 2 = 102, exceeding the default limit. The JSON construction specification makes this distinction between fields and arguments explicit.

Accepting variadic arguments does not remove the call limit. The function-call parser checks the argument-list length before resolving the target function. An oversized call never reaches the function body.

This counts arguments supplied directly to one call. It does not impose a 50-key limit on JSON objects.

Changing max_function_args reaches into C-extension compatibility

Read the connected server’s limit with the following SQL. SHOW displays current values without changing settings.

SQL
-- Read the connected server version and function-argument limit.
SHOW server_version;
SHOW max_function_args;

max_function_args is a read-only preset, defaulting to 100 and determined by FUNC_MAX_ARGS when the server is built. Neither SET nor an edit to postgresql.conf increases it. See the preset-option documentation.

Editing the constant is possible. However, pg_config_manual.h requires a full backend recompile, including user-defined C functions. This particular change does not require initdb; the header also warns that unnecessarily large values waste memory and processing time.

C extensions matter because PostgreSQL checks a magic block when loading shared libraries. That ABI information includes FUNC_MAX_ARGS. A server built with 200 and a library built with 100 are rejected as incompatible, even within the same major version. Raising the limit therefore means budgeting for matching C-extension builds and testing that they load.

Pass a row to to_jsonb instead of adding arguments for every column

Before rebuilding, consider the shape of the desired data. If it is a row, pass that row as one argument to to_jsonb, which converts composite values into JSON objects. See the row-to-JSON conversion rules.

This minimal example selects the output columns in a subquery and converts its row. It creates no tables and updates no data.

SQL
-- Convert a row containing selected columns through one JSONB argument.
SELECT to_jsonb(payload)
FROM (
  SELECT 42 AS id, true AS active, 12.5::numeric AS amount
) AS payload;

The result contains id, active, and amount with JSON number, boolean, and number values. Adding columns leaves the outer to_jsonb call with just one argument: payload.

For an actual table, explicitly selecting output columns and aliases is a useful design choice. Converting a whole row directly allows added columns to become output fields too. If an API needs a fixed response shape, selecting columns before conversion gives you control over that contract.

Match an array to the variadic interface and required value types

Other workloads need to pass many values of the same type. For a compatible variadic function, specifying VARIADIC at the call site passes an array as a unit. Simply supplying ARRAY[...] does not use the same argument-resolution behavior. The variadic-function documentation explains the distinction.

SQL
-- Pass a text array to the variadic input and concatenate its elements.
SELECT concat(VARIADIC ARRAY[10::text, 20::text, 30::text]);

This produces the string 102030. It does not make arbitrary functions accept arrays: the receiving function must support the corresponding variadic input.

Likewise, putting every key and value into text[] for jsonb_build_object makes the values strings. Avoiding the argument limit would not preserve an output contract that requires JSON numbers or booleans. For a row containing columns of different types, the to_jsonb approach is a candidate.

Start by locating the oversized call in the generated SQL. Then decide whether its input should represent a row or a collection of same-type values. Reshaping that input can avoid a configuration change that requires rebuilding C extensions. Choosing how a data group becomes an argument is a practical way to keep the maintenance scope small.

Source

Share

Related Articles

These articles share nearby categories or tags, so you can keep reading along the same thread.