PostgreSQL Error 2200G: most specific type mismatch
PostgreSQL error 2200G: most specific type mismatch occurs when the database engine cannot resolve a single, unambiguous "most specific type" among values being processed together in a type-sensitive context. This error commonly surfaces in XML functions, UNION queries involving domain or composite types, and overloaded function calls where type resolution becomes ambiguous. Understanding and resolving this error requires explicit type casting and a solid grasp of PostgreSQL's type hierarchy system.
Top 3 Causes
1. XML Functions with Mixed Types
PostgreSQL XML functions like XMLFOREST and XMLELEMENT require consistent types across their arguments. When you pass values of different types without explicit casting, the engine fails to determine the most specific common type.
-- Problematic query: mixing INTEGER, TEXT, NUMERIC
SELECT XMLFOREST(
employee_id, -- INTEGER
department, -- TEXT
salary -- NUMERIC
)
FROM employees;
-- ERROR: 2200G most specific type mismatch
-- Fix: explicitly cast all values to TEXT
SELECT XMLFOREST(
employee_id::TEXT AS "employeeId",
department::TEXT AS "department",
salary::TEXT AS "salary"
)
FROM employees;
2. UNION Queries with Incompatible Column Types
When combining result sets using UNION or UNION ALL, corresponding columns must share a resolvable common type. Domain types or composite types with no clear hierarchy cause the 2200G error.
-- Problematic: DATE vs TIMESTAMP in the same column position
SELECT order_id, customer_name, created_at::DATE AS event_date
FROM orders
UNION ALL
SELECT product_id, product_name, updated_at::TIMESTAMP AS event_date
FROM products;
-- ERROR: 2200G most specific type mismatch
-- Fix: cast both columns to the same type
SELECT order_id, customer_name, created_at::TIMESTAMP AS event_date
FROM orders
UNION ALL
SELECT product_id, product_name, updated_at::TIMESTAMP AS event_date
FROM products;
3. Ambiguous Function Overloading Resolution
PostgreSQL supports function overloading, but when argument types match multiple signatures and no single "most specific" version can be determined, error 2200G is raised.
-- Two overloaded functions
CREATE FUNCTION calc(val INTEGER) RETURNS TEXT AS $$
SELECT 'int:' || val::TEXT;
$$ LANGUAGE SQL;
CREATE FUNCTION calc(val NUMERIC) RETURNS TEXT AS $$
SELECT 'num:' || val::TEXT;
$$ LANGUAGE SQL;
-- Ambiguous call
SELECT calc(100); -- May raise 2200G
-- Fix: use explicit casting to target the correct overload
SELECT calc(100::INTEGER); -- Resolves to INTEGER version
SELECT calc(100::NUMERIC); -- Resolves to NUMERIC version
-- Verify available overloads
SELECT proname, pg_get_function_arguments(oid) AS args
FROM pg_proc
WHERE proname = 'calc';
Quick Fix Solutions
- Always cast explicitly — never rely on implicit type coercion in XML functions, UNION queries, or overloaded function calls.
-
Use
pg_typeof()to inspect actual column types before building complex queries. - Normalize types at the schema level to avoid domain type conflicts in set operations.
-- Inspect column types before writing complex queries
SELECT column_name, data_type, udt_name
FROM information_schema.columns
WHERE table_name = 'employees'
ORDER BY ordinal_position;
-- Use pg_typeof() inline for quick type checking
SELECT pg_typeof(employee_id), pg_typeof(salary)
FROM employees
LIMIT 1;
Prevention Tips
-
Enforce explicit casting conventions in your team's SQL style guide. Require
::typeorCAST(x AS type)in all XML-related, UNION, and function call code. Include type consistency checks in your code review checklist. -
Automate type validation in CI/CD by running schema and query type checks before deployment. Use
pg_typeof()in unit tests to assert expected return types and catch mismatches early in the development cycle.
-- Simple type assertion pattern for automated testing
DO $$
DECLARE v_type TEXT;
BEGIN
SELECT pg_typeof(salary)::TEXT INTO v_type FROM employees LIMIT 1;
IF v_type != 'numeric' THEN
RAISE EXCEPTION 'Type check failed: expected numeric, got %', v_type;
END IF;
RAISE NOTICE 'Type check passed: %', v_type;
END;
$$;
📖 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)