The "Cache lookup failed for function" error occurs when PostgreSQL cannot find a function in its system catalog (pg_proc). This typically happens after dropping and recreating functions while active connections reference the old function, or in cases of system catalog corruption.
PostgreSQL maintains an in-memory cache of system catalog objects for performance. When a query tries to execute a function, PostgreSQL looks it up in the cache. This error indicates the function entry is missing from the system catalog—either because the function was dropped while in use, the cache is stale, or the catalog is corrupted. This is generally an indication of improper schema management or potential data corruption.
The safest approach is to use CREATE OR REPLACE FUNCTION, which preserves the function OID and prevents cache invalidation:
WRONG (causes cache issues):
DROP FUNCTION my_function(int);
CREATE FUNCTION my_function(int) RETURNS text AS $$
BEGIN
RETURN 'updated';
END;
$$ LANGUAGE plpgsql;CORRECT (preserves OID):
CREATE OR REPLACE FUNCTION my_function(int) RETURNS text AS $$
BEGIN
RETURN 'updated';
END;
$$ LANGUAGE plpgsql;CREATE OR REPLACE keeps the same function OID, so existing sessions and cached references remain valid.
If you've already dropped a function, existing connections may have stale cache entries. Terminate all connections using that function:
-- Find sessions using the function's schema
SELECT pid, usename, state FROM pg_stat_activity WHERE state != 'idle';
-- Terminate specific sessions
SELECT pg_terminate_backend(pid) FROM pg_stat_activity
WHERE usename = 'app_user' AND state != 'idle';For applications:
1. Stop the application
2. Wait 10-30 seconds for all connections to close
3. Recreate the function using CREATE OR REPLACE
4. Restart the application
This forces applications to reconnect and clear their function cache.
Query the pg_proc system catalog to confirm the function exists:
-- Find the function
SELECT oid, proname, pronamespace, pronargs
FROM pg_proc
WHERE proname = 'my_function';
-- Check function signature
SELECT pg_get_functiondef('my_function(int)'::regprocedure);
-- List all functions in a schema
SELECT p.proname, pg_get_functiondef(p.oid)
FROM pg_proc p
JOIN pg_namespace n ON p.pronamespace = n.oid
WHERE n.nspname = 'public';If the function doesn't exist, recreate it. If it does exist, check that dependent functions have the correct signature.
In rare cases of catalog corruption, reindex the pg_proc catalog (requires superuser and database in single-user mode):
# Stop PostgreSQL
sudo systemctl stop postgresql
# Run in single-user mode
sudo -u postgres /usr/lib/postgresql/[VERSION]/bin/postgres -D /var/lib/postgresql/[VERSION]/main --singleThen in the single-user session:
REINDEX INDEX pg_proc_oid_index;
REINDEX INDEX pg_proc_proname_nsp_index;Type ^D (Ctrl+D) to exit and restart PostgreSQL normally.
Important: Only do this if you suspect actual catalog corruption, which is extremely rare.
If a PL/pgSQL function calls other functions, ensure all called functions exist:
-- View the function source code
SELECT prosrc FROM pg_proc WHERE proname = 'my_function';
-- List function dependencies
SELECT DISTINCT dependent.proname as depending_function,
dependency.proname as called_function
FROM pg_depend
JOIN pg_proc dependent ON pg_depend.refobjid = dependent.oid
JOIN pg_proc dependency ON pg_depend.objid = dependency.oid
WHERE pg_depend.objid IN (
SELECT oid FROM pg_proc WHERE proname = 'my_function'
);Ensure all called functions are created before the calling function, and always use full schema qualification (e.g., schema.function_name()) to avoid ambiguity.
For future deployments, use one of these safe patterns:
Option 1: CREATE OR REPLACE (recommended for compatible changes)
CREATE OR REPLACE FUNCTION my_function(int) RETURNS text AS $$ ... $$ LANGUAGE plpgsql;Option 2: Wrapper pattern (for incompatible signature changes)
-- Keep old function as wrapper
CREATE OR REPLACE FUNCTION my_function(int) RETURNS text AS $$
SELECT my_function_v2($1);
$$ LANGUAGE sql;
-- Create new implementation
CREATE FUNCTION my_function_v2(int) RETURNS text AS $$ ... $$ LANGUAGE plpgsql;Option 3: Transaction-wrapped drop/create (only in single-user mode or maintenance window)
BEGIN;
DROP FUNCTION IF EXISTS my_function(int);
CREATE FUNCTION my_function(int) RETURNS text AS $$ ... $$ LANGUAGE plpgsql;
COMMIT;
-- Then force all clients to reconnectAlways plan function changes during maintenance windows with no active connections.
The cache lookup error is fundamentally about PostgreSQL's internal object identification system. Each function has a unique OID (object identifier). When PostgreSQL compiles a query, it stores the OID of referenced functions. If a function is dropped and a new one is created with the same name, the new function gets a different OID. Existing compiled queries or cached plans still reference the old OID, causing the lookup to fail. This is why CREATE OR REPLACE is preferred—it keeps the same OID. In distributed systems or with connection pooling, this becomes even more critical. Tools like PgBouncer or pgpool can cache query plans, making proper function replacement essential. System catalog corruption that causes this error is usually preceded by PostgreSQL startup crashes or storage layer failures. If you encounter persistent "cache lookup failed" errors without recent function modifications, run REINDEX on system tables and check PostgreSQL logs for earlier crash recovery messages.
insufficient columns in unique constraint for partition key
How to fix "insufficient columns in unique constraint for partition key" in PostgreSQL
ERROR 42501: must be owner of table
How to fix "must be owner of table" in PostgreSQL
trigger cannot change partition destination
How to fix "Trigger cannot change partition destination" in PostgreSQL
SSL error: certificate does not match host name
SSL error: certificate does not match host name in PostgreSQL
No SSL connection
No SSL connection to PostgreSQL