PostgreSQL Error 42P18: indeterminate datatype
PostgreSQL error 42P18 occurs when the query parser or planner cannot determine the data type of an expression at parse time. Because PostgreSQL is a strongly typed system, every expression must have a resolved type before an execution plan can be built. This most commonly happens with untyped NULL literals, unbound parameters ($1, $2), or empty array literals.
Top 3 Causes
1. Untyped NULL Literals
Using a bare NULL without a type cast in contexts like COALESCE, UNION, or CASE confuses the planner because NULL is inherently typeless.
-- ❌ Fails: cannot determine type of NULL
SELECT COALESCE(NULL, NULL);
-- ❌ Fails: UNION with ambiguous NULLs
SELECT NULL
UNION ALL
SELECT NULL;
-- ✅ Fixed: explicit type casts
SELECT COALESCE(NULL::INTEGER, NULL::INTEGER);
SELECT NULL::TEXT AS col
UNION ALL
SELECT NULL::TEXT;
2. Untyped Bind Parameters in Prepared Statements
When you use $1, $2, etc., in a prepared statement without specifying their types, PostgreSQL cannot infer what type to expect, especially when the parameter appears without enough surrounding context.
-- ❌ Fails: $1 type is indeterminate
PREPARE my_stmt AS SELECT $1;
-- ✅ Fixed: declare parameter types explicitly
PREPARE my_stmt(INTEGER) AS SELECT $1;
EXECUTE my_stmt(42);
-- ✅ Fixed: multiple typed parameters
PREPARE user_lookup(INTEGER, TEXT) AS
SELECT * FROM users
WHERE id = $1 OR username = $2;
EXECUTE user_lookup(1, 'alice');
3. Empty or Untyped Array Literals
An empty array ARRAY[] has no element type, so PostgreSQL cannot determine what kind of array it is. This is a frequent issue when passing arrays to functions or operators.
-- ❌ Fails: element type of ARRAY[] is unknown
SELECT ARRAY[];
-- ❌ Fails: unnest cannot determine element type
SELECT unnest(ARRAY[]);
-- ✅ Fixed: cast the array to a specific type
SELECT ARRAY[]::INTEGER[];
SELECT ARRAY[]::TEXT[];
SELECT unnest(ARRAY[]::TEXT[]);
SELECT unnest(ARRAY['a', 'b', 'c']::TEXT[]);
-- ✅ Fixed: ROW constructor with explicit casts
SELECT ROW(NULL::INTEGER, NULL::TEXT);
Quick Fix Solutions
Apply explicit type casts wherever PostgreSQL cannot infer a type on its own:
-- Cast NULL in any ambiguous context
NULL::target_type
-- Cast arrays
ARRAY[]::element_type[]
-- Cast parameters in ad-hoc queries
SELECT $1::TEXT;
-- Use PREPARE with explicit parameter types
PREPARE stmt(TYPE1, TYPE2) AS ...;
For application-level fixes, always pass type OIDs when using client libraries:
# psycopg2 example: use %s with explicit cast in SQL
cur.execute("SELECT %s::integer", (42,))
Prevention Tips
Always cast NULL and empty arrays explicitly. Adopt a team coding standard that requires explicit type casts on all
NULLliterals and empty array expressions. Integrate a SQL linter such as SQLFluff into your CI/CD pipeline to catch violations automatically before they reach production.Declare parameter types in all Prepared Statements. Make it a habit to always include type declarations in
PREPAREstatements and to pass type OIDs explicitly in your client library bindings (JDBC, libpq, psycopg2, etc.). Test prepared statements in a staging environment before deploying to production to catch42P18errors early.
📖 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)