Diagnostic Queries
Symptoms
You tried to build an expression index (or an index predicate) using a function that is not declared IMMUTABLE. An index value must never change for the same input, so PostgreSQL rejects volatile/stable functions with SQLSTATE 42P17 (invalid_object_definition).
- Triggered at
CREATE INDEXtime, before the index is built. - Classic example: indexing
lower(col)works, butnow()ortimezone()-dependent expressions do not. - Casts that depend on locale/timezone can also be non-immutable.
What the server log shows
ERROR: functions in index expression must be marked IMMUTABLE
Why PostgreSQL raises this — what the manual says
As Section 11.7 Indexes on Expressions explains:
Any function used in an index expression must be declared IMMUTABLE, because the value is computed once when the row is indexed and must never change for the same input; mark the function IMMUTABLE only if its result truly depends solely on its arguments, otherwise the index would silently become inconsistent.
An index physically stores precomputed expression results. If the function could return different output for the same input (because it reads the clock, the timezone GUC, or table data), stored entries would become wrong. PostgreSQL therefore requires IMMUTABLE and raises 42P17 otherwise.
Common causes
- Indexing a timestamp cast that depends on the session timezone (e.g.
col::dateon atimestamptz). - Using a STABLE or VOLATILE function in the index expression.
- A custom function that was not (correctly) marked IMMUTABLE.
How to fix it
- Use an immutable form: index
(col AT TIME ZONE 'UTC')::dateinstead ofcol::date. - If your function truly is immutable, declare it so:
CREATE FUNCTION … IMMUTABLE;(only if results never depend on outside state). - Reconsider whether the expression should be indexed at all, or store a generated column instead.
Related & next steps
Reference: PostgreSQL 18 Section 11.7 “Indexes on Expressions”.
Thanks — noted. This helps keep the database accurate.