SQLSTATE 42P17 ERROR Class 42: Syntax Error or Access Rule Violation

invalid_object_definition functions in index expression must be marked IMMUTABLE — 42P17

PostgreSQL error "functions in index expression must be marked IMMUTABLE" (SQLSTATE 42P17): what it means, common causes, and how to fix it.

PG 12, 13, 14, 15, 16, 17, 18 Official docs
Last reviewed May 2025 Grounded in source

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 INDEX time, before the index is built.
  • Classic example: indexing lower(col) works, but now() or timezone()-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::date on a timestamptz).
  • Using a STABLE or VOLATILE function in the index expression.
  • A custom function that was not (correctly) marked IMMUTABLE.

How to fix it

  1. Use an immutable form: index (col AT TIME ZONE 'UTC')::date instead of col::date.
  2. If your function truly is immutable, declare it so: CREATE FUNCTION … IMMUTABLE; (only if results never depend on outside state).
  3. 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”.

Was this helpful?