The PostgreSQL "most_specific_type_mismatch" error (2200G) occurs when UNION, CASE, INTERSECT, or EXCEPT queries combine columns or expressions with incompatible data types that cannot be implicitly coerced to a common type. Fixing requires explicitly casting mismatched columns to compatible types.
The "most_specific_type_mismatch" error (2200G) occurs when PostgreSQL's type resolution system encounters incompatible data types in multi-part queries. This typically happens with UNION, INTERSECT, EXCEPT, or CASE statements where the database cannot find a common type that all branches can be converted to. Unlike some databases that perform automatic type coercion, PostgreSQL requires that all branches of a set operation return compatible types. When you combine multiple SELECT statements with UNION or use CASE expressions with different branch types, PostgreSQL applies strict type checking. If it cannot find a common supertype through implicit casting rules, it raises this error. The type resolution algorithm checks: (1) if all inputs are the same type; (2) if any are domain types; (3) if all are unknown; or (4) if there exists a type all inputs can be implicitly cast to. If none of these apply, you get 2200G.
Enable query logging in PostgreSQL to see the failing SQL statement. Check application error messages and PostgreSQL logs (typically /var/log/postgresql/ on Unix systems, or check the server logs in pgAdmin). Look for the query triggering 2200G and note which operation (UNION, CASE, etc.) is involved.
For UNION queries, document the data type of each column in every SELECT branch. Use psql or a GUI tool to inspect column types:
-- Check column types in a table
\d your_table
-- Problematic example:
SELECT id, name FROM users -- id: integer, name: text
UNION
SELECT product_id, description FROM products; -- product_id: text, description: textIn this example, id (integer) and product_id (text) are incompatible because integer cannot be implicitly cast to text in a UNION context.
Add explicit type casts using the ::type syntax (PostgreSQL shorthand) or CAST() function:
-- INCORRECT: type mismatch
SELECT id, name FROM users
UNION
SELECT product_id, description FROM products;
-- CORRECT: cast id to text
SELECT id::text, name FROM users
UNION
SELECT product_id, description FROM products;
-- Alternative using CAST()
SELECT CAST(id AS text), name FROM users
UNION
SELECT product_id, description FROM products;Choose the target type based on: (1) the most general type needed, (2) whether the cast preserves data (e.g., numeric to text is safe; text to numeric may fail).
Problematic CASE with mixed types:
-- INCORRECT: branches return integer and text
SELECT CASE
WHEN status = 'active' THEN 1
ELSE 'inactive'
END;Fixed by casting all branches to the same type:
-- CORRECT: all branches return text
SELECT CASE
WHEN status = 'active' THEN '1'::text
ELSE 'inactive'
END;
-- Or cast to numeric
SELECT CASE
WHEN status = 'active' THEN 1::numeric
ELSE 0
END;Ensure ALL branches (including ELSE) return the same type or compatible types.
The GREATEST and LEAST functions require compatible argument types:
-- INCORRECT: mixing integer and text
SELECT GREATEST(user_id, user_name);
-- CORRECT: cast to common type
SELECT GREATEST(user_id::text, user_name);All arguments must be convertible to a common type.
Understanding PostgreSQL's type coercion rules helps you write better queries. Key implicit casts:
- integer -> numeric, bigint, real, double precision
- text -> varchar (and vice versa)
- smallint -> integer, bigint, numeric
Note: integer to text is NOT an implicit cast; you must use explicit ::text.
Consult the official PostgreSQL documentation: https://www.postgresql.org/docs/current/typeconv.html
Execute the modified query in a development environment:
-- Test your corrected query
EXPLAIN ANALYZE
SELECT id::text, name FROM users
UNION
SELECT product_id, description FROM products;Verify that the query executes without errors and returns the expected result set. Use EXPLAIN ANALYZE to check performance.
PostgreSQL's type resolution follows specific rules. For UNION and similar constructs: (1) if all inputs are the same type, use that type; (2) ignore unknown types; (3) if only unknowns remain, default to text; (4) otherwise, find a common supertype that all inputs can implicitly cast to. Domain types are treated as their base types during resolution.
Nested UNIONs can be tricky: the innermost UNION resolves first, and its result type is used in the next outer UNION. Example: SELECT NULL UNION SELECT NULL UNION SELECT 1 fails because the inner SELECT NULL UNION SELECT NULL resolves as text, then text and integer have no common supertype.
Fix nested UNIONs by explicitly casting NULL:
SELECT NULL::int
UNION
SELECT NULL::int
UNION
SELECT 1;Performance note: casting columns in WHERE clauses can prevent index usage. For example, WHERE id::text = '123' may not use an index on id. Instead, align your schema design or cast the other operand: WHERE id = 123::int. Use EXPLAIN to verify index usage.
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