# 42P16 — Invalid table definition

> Source-backed reference for PostgreSQL SQLSTATE 42P16.
---

# 42P16 — Invalid table definition

## At a glance {#at-a-glance}

`42P16` (**invalid_table_definition**) A table definition can violate partition-key, collation, or primary-key rules.

<!-- BEGIN SQLSTATE FACTS: generated by scripts/generate.py; do not edit -->

| Field | Value |
| --- | --- |
| SQLSTATE | `42P16` |
| Condition | `invalid_table_definition` |
| Status | `active` |
| Known present by | `7.4` |
| Locked snapshots | `9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3` |
| Macros | `ERRCODE_INVALID_TABLE_DEFINITION` |
| Aliases | `—` |

<!-- source facts: data/errcodes/42P16.json -->
<!-- END SQLSTATE FACTS -->

## Meaning {#meaning}

Table-definition checks use this condition for several relation-shape violations. Core 18.6 examples reject pseudo-types in partition keys, missing collation for a collatable partition key, and multiple primary keys.

## Diagnosis {#diagnosis}

Use the exact message to identify the table and column. Inspect pg_attribute/pg_type for the partition key type, determine the collation explicitly for collatable types, and list existing primary constraints before changing DDL.

## Response {#response}

Change only the conflicting table definition: use a supported concrete partition-key type, add an explicit COLLATE where the source requires it, or retain one intended primary key and remove the duplicate declaration from the migration. If this ERROR occurs inside an explicit transaction, `ROLLBACK` or `ROLLBACK TO` a pre-error savepoint before issuing the corrected DDL; do not keep sending table changes in the aborted transaction.

## Messages {#messages}

Representative source messages include: message: `partition key column %s has pseudo-type %s`; message: `no collation was derived for partition key column %s with collatable type %s`; HINT: `Use the COLLATE clause to set the collation explicitly.`; message: `multiple primary keys for table "%s" are not allowed`. Placeholders are filled by the actual object, column, or parameter.

## Versions {#versions}

The locked catalogue shows this condition by PostgreSQL 7.4; behavior here is fixed to PostgreSQL 18.6 source. Catalogue presence is a range boundary, not proof that every message or feature began in that release.

## Related {#related}

- [`42P07`](../42p07/)
- [`42P17`](../42p17/)

## Sources {#sources}

Source messages, line anchors, and evidence limits are recorded in [authored evidence](../data/evidence/42p16.json).

- `src/backend/catalog/heap.c:576-580` ([fixed source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/catalog/heap.c#L576-L580))
- `src/backend/catalog/heap.c:697-702` ([fixed source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/catalog/heap.c#L697-L702))
- `src/backend/catalog/index.c:218-221` ([fixed source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/catalog/index.c#L218-L221))
