This error occurs when performing numeric operations on JSON values that are not actually numeric types. Fix by validating JSON types before operations, using error-suppressing operators, or specifying proper error handling modes.
PostgreSQL throws the "Non-numeric SQL/JSON item" error when you attempt to perform a numeric operation on a JSON/JSONB value that contains a non-numeric type such as a string, object, or array. This commonly happens when using SQL/JSON path expressions with arithmetic operators, casting JSON values to numeric types, or using numeric functions on JSON data without first validating the data type. The error prevents type mismatches that could corrupt calculations or produce unexpected results.
First, inspect your JSON data to confirm it contains numeric values where you expect them. Use jsonb_typeof() to check the JSON type:
SELECT jsonb_typeof(data->>'score') FROM table_name LIMIT 5;If the result is "string" instead of "number", your JSON contains string values that cannot be used in numeric operations directly.
Use lax mode (the default) in jsonpath expressions to automatically suppress numeric errors:
SELECT jsonb_path_query_array(
data,
'lax $.items[*].score'
) FROM table_name;Lax mode implicitly adapts the queried data and suppresses non-matching structural errors, returning NULL or empty sequences instead of throwing an error.
The @? and @@ operators automatically suppress numeric errors:
-- Check if a path exists without numeric errors
SELECT * FROM table_name
WHERE data @? '$.score > 50';
-- Return matching items while suppressing errors
SELECT jsonb_path_query_array(data, '$.items[*] ? (@ > 50)') FROM table_name;These operators silently ignore numeric type mismatches instead of raising errors.
For functions that support it, use the silent argument set to true:
SELECT json_query(
data,
'$.score',
RETURNING numeric,
SILENT
) FROM table_name;This tells PostgreSQL to suppress numeric errors and return NULL instead of throwing an error when encountering non-numeric JSON items.
Before performing numeric operations, validate and convert JSON values safely using CASE statements:
SELECT
CASE
WHEN jsonb_typeof(data->>'score') = 'number'
THEN (data->>'score')::numeric
ELSE NULL
END AS score_numeric
FROM table_name;Alternatively, use jsonb_extract_path_text() with type validation:
SELECT
COALESCE(
(data->>'score')::numeric,
0
) AS score
FROM table_name
WHERE data->>'score' ~ '^\d+(\.\d+)?$';If you explicitly need strict mode to catch type errors during development, use it but handle exceptions:
BEGIN
SELECT jsonb_path_query_array(
data,
'strict $.score + 10'
) FROM table_name;
EXCEPTION WHEN others THEN
RAISE NOTICE 'Non-numeric JSON item encountered: %', SQLERRM;
END;Strict mode will raise errors for structural issues, but this is typically only useful during data validation and debugging, not in production queries.
JSON path mode defaults to lax, which is lenient with non-numeric values and is the safest choice for production queries against varying JSON structures. Strict mode raises errors on structural mismatches and is better suited for data validation scripts. When casting JSON to numeric types directly (e.g., (data->'value')::numeric), PostgreSQL will throw an error if the value is a non-numeric JSON type; use conditional logic or the validation approach in Step 5 to handle this gracefully. In PostgreSQL 14+, the json_query() and json_value() functions provide more sophisticated error handling with the RETURNING and SILENT clauses. For complex JSON transformations, consider normalizing and validating your JSON schema at insert time rather than trying to handle all type variations at query time.
ERROR: syntax error at end of input
Syntax error at end of input in PostgreSQL
Bind message supplies N parameters but prepared statement requires M
Bind message supplies N parameters but prepared statement requires M in PostgreSQL
Multidimensional arrays must have sub-arrays with matching dimensions
Multidimensional arrays must have sub-arrays with matching dimensions
ERROR: value too long for type character varying
Value too long for type character varying
insufficient columns in unique constraint for partition key
How to fix "insufficient columns in unique constraint for partition key" in PostgreSQL