42P01 — undefined_table
42P01 is PostgreSQL's undefinedtable condition in Class 42, syntaxerrororaccessruleviolation. The name is historical: the failing reference can be a table, view, materialized view, foreign table, or another relation name that the parser cannot resolve in the current namespace.
English manual coverage begins with PostgreSQL 8.1. Source history and runtime observations have their own recorded version boundaries.
Reading PG 18·Select a recorded version
- aliases
- Unknown
- class name
- Syntax Error or Access Rule Violation
- condition name
- undefined_table
- lang
- en
- sqlstate
- 42P01
Definition PG 18
At a glance {#at-a-glance}
42P01 is PostgreSQL's undefined_table condition in Class 42, syntax_error_or_access_rule_violation. The name is historical: the failing reference can be a table, view, materialized view, foreign table, or another relation name that the parser cannot resolve in the current namespace.
The ordinary diagnostic is relation "%s" does not exist for an unqualified reference or relation "%s.%s" does not exist for a qualified reference. The parser reports the SQLSTATE before execution of the query; in an autocommit connection the error does not leave a failed transaction behind.
The representative case queries a schema-qualified relation that does not exist, then creates a valid relation and reads it. PostgreSQL 18.6 and the isolated PostgreSQL 10.21 target both returned 42P01, kept the connection IDLE, and accepted the corrected query. The run IDs and assertions are retained in the public evidence JSON.
Meaning and trigger paths {#meaning}
During parse analysis PostgreSQL resolves each relation through the active namespace and search_path. If a qualified name is absent, parse_relation.c emits the two-part message; if an unqualified name is absent, it emits the one-part form. A misspelled name, a migration that has not run, a wrong database, a changed search_path, or a quoted identifier with different case can all lead to this same SQLSTATE.
This is a name-resolution error, not proof that a physical table was deleted. A relation can exist in another schema or database, and a role can lack the privileges needed to see or use it. Conversely, creating a table with a guessed name can conceal a deployment or quoting error.
The parser also uses 42P01 for some invalid references to a FROM item and for a forward reference to a common-table expression, with different detail or hint text. Use the complete message and context to distinguish those forms from a missing relation.
Messages and diagnostics {#messages}
The runner's operation is a schema-qualified lookup followed by a corrected relation. The harness supplies the disposable schema name; the query shape is:
SELECT * FROM does_not_exist;
CREATE TABLE exists(id integer PRIMARY KEY);
SELECT count(*) FROM exists;
PostgreSQL 18.6 returned:
SQLSTATE: 42P01
severity: ERROR
message_primary: relation "c42p01_missing_relation.does_not_exist" does not exist
source: parse_relation.c / parserOpenTable / line 1480
The PG10 target used the same primary message with source line 1159. The qualified form preserves both schema and relation in the message. For an unqualified reference, the fixed source template is relation "%s" does not exist; a future CTE or invalid FROM reference can add detail or a hint.
Diagnosis {#diagnosis}
Record SQLSTATE, primary message, detail, hint, statement position, current database, role, and search_path. Check the exact spelling and quoting used by the application. Query pg_class/pg_namespace or to_regclass() through an administrative or appropriately privileged connection to determine where the relation exists.
Compare the deployed migration revision with the connection's database and schema. A pooled connection can carry a different search_path from the session used during setup. If the object is intended to be temporary or session-local, confirm that the query runs in the same session that created it.
The representative error was autocommit and left the connection IDLE; the corrected query returned count 0 and remained IDLE. An explicit transaction can still become INERROR if the missing relation is referenced inside that transaction, so record status rather than assuming that all 42P01 cases are harmless to the surrounding work.
Response and repair {#response}
Repair the name-resolution cause in deployment or application configuration:
- Select the intended schema explicitly or set and verify
search_pathfor the session. - Apply the missing migration in the correct database before serving queries.
- Preserve case-sensitive identifiers with exact double quoting, or rename them to a consistent convention after checking dependents.
- Use
to_regclass()or an equivalent preflight only when a missing object is an expected branch; do not silently create a replacement relation for an unexpected deployment failure.
After correcting the relation, run the original query again and verify its result and transaction status. A successful CREATE TABLE or a new connection alone does not prove that every application session resolves the same object.
Versions and boundaries {#versions}
The catalogue has a definition-presence observation for 42P01 at PostgreSQL 7.4 and through the locked 8.4.22 pre-9.0 definitions, then in every listed formal snapshot through PostgreSQL 18.6 and the PostgreSQL 19 Beta 3 preview. This is a definition-only presence boundary, not an exact implementation introduction or runtime-use claim. No condition definition change is recorded in the scanned range.
The missing-relation case passed on PostgreSQL 18.6 and 10.21. Source line numbers and parser hints differ by release and reference form. This page covers a schema-qualified absent relation and a valid follow-up query, not every namespace or access-rule path that can use 42P01.
Related {#related}
42P02 — undefined_parameter covers a missing query parameter. 3F000 — invalid_schema_name covers an invalid schema name. 42501 — insufficient_privilege is an access failure after name resolution. 57014 — query_canceled can interrupt a corrective query but has a different cause.
Sources {#sources}
Structured evidence is recorded in the public evidence JSON. Source records are fixed to PostgreSQL commit 724edf9bde9d356724ad384a2e196edc3c9f80f7; runtime records retain both target IDs and structured observations.
src.errcodes.18.6—errcodes.txtsrc.parse-relation.18.6—parse_relation.csrc.namespace.18.6—namespace.cdoc.ddl.18.6— Schemas- Runtime:
42P01-registry-final-20260909on latest and pg10; structured observations are in the public evidence JSON
Compare versions
SQLSTATE evidence and recorded runtime versions
cases · missing_relation
{
"assertions": [
"SQLSTATE is 42P01",
"The missing relation is named in the diagnostic",
"A valid query succeeds after correcting the relation name"
],
"case_id": "missing_relation",
"cleanup": "Drop the case schema with an owner connection.",
"has_snippet": true,
"position": 0,
"preconditions": [
"A disposable schema name that has no relation"
],
"repair": "Check schema qualification, search_path, migrations, and case-sensitive quoting before creating or renaming objects.",
"trigger": "Select from a relation that does not exist.",
"versions": [
"10",
"18"
]
}claims · identity.class-and-condition
{
"claim_id": "identity.class-and-condition",
"limits": "The historical condition name covers relation lookup failures beyond a literal table.",
"method": "Read the Class 42 section and 42P01 row in the frozen errcodes.txt snapshot.",
"position": 0,
"runtime": [],
"sources": [
"src.errcodes.18.6"
],
"statement": "42P01 is the undefined_table condition in Class 42 syntax_error_or_access_rule_violation."
}claims · mechanism.relation-lookup
{
"claim_id": "mechanism.relation-lookup",
"limits": "The displayed relation name depends on qualification, search_path, quoting, and the parse context.",
"method": "Trace namespace.c lookup and parserOpenTable qualified and unqualified error branches in the fixed source, then check the protocol field reference.",
"position": 1,
"runtime": [],
"sources": [
"src.namespace.18.6",
"src.parse-relation.18.6",
"doc.ddl.18.6",
"doc.protocol.18"
],
"statement": "The parser reports ERRCODE_UNDEFINED_TABLE with relation \"%s.%s\" does not exist for a qualified relation and relation \"%s\" does not exist for an unqualified relation."
}claims · runtime.missing-relation-recovery
{
"claim_id": "runtime.missing-relation-recovery",
"limits": "This case does not distinguish migration races, search_path changes, permissions, or all relation kinds.",
"method": "Execute the missing query, inspect diagnostics and status, create the schema-qualified relation, and assert a valid follow-up query.",
"position": 2,
"runtime": [],
"sources": [
"case-manifest.42P01",
"snippet-registry.42P01.final",
"runtime.42P01-registry-final-20260909.latest",
"runtime.42P01-registry-final-20260909.pg10"
],
"statement": "A missing relation query returned SQLSTATE 42P01 while autocommit remained IDLE; creating the intended relation and querying it returned count 0 on both targets."
}claims · versions.catalogue-boundary
{
"claim_id": "versions.catalogue-boundary",
"limits": "The first scanned release is a lower bound, not an asserted introduction version.",
"method": "Read the manifest snapshots and definition references for the code.",
"position": 3,
"runtime": [],
"sources": [
"manifest.42P01"
],
"statement": "The locked catalogue records 42P01 in every listed formal snapshot from 9.0.23 through 18.6 and in 19beta3; pre-9.0 history is not scanned."
}messages · message.qualified-relation
{
"limits": "The qualified form is selected when the parser has a schema-qualified relation reference.",
"message_id": "message.qualified-relation",
"path": "",
"position": 0,
"raw": {
"id": "message.qualified-relation",
"limits": "The qualified form is selected when the parser has a schema-qualified relation reference.",
"primary_template": "relation \"%s.%s\" does not exist",
"severity_source": "explicit ERROR",
"sources": [
"src.parse-relation.18.6"
],
"sqlstate": "42P01"
},
"severity": "explicit ERROR",
"sources": [
"src.parse-relation.18.6"
],
"templates": [
{
"kind": "primary",
"literal": "relation \" . \" does not exist",
"position": 0,
"role": "",
"template": "relation \"%s.%s\" does not exist"
}
]
}messages · message.unqualified-relation
{
"limits": "The unqualified form is selected when lookup through the active namespace fails.",
"message_id": "message.unqualified-relation",
"path": "",
"position": 1,
"raw": {
"id": "message.unqualified-relation",
"limits": "The unqualified form is selected when lookup through the active namespace fails.",
"primary_template": "relation \"%s\" does not exist",
"severity_source": "explicit ERROR",
"sources": [
"src.parse-relation.18.6"
],
"sqlstate": "42P01"
},
"severity": "explicit ERROR",
"sources": [
"src.parse-relation.18.6"
],
"templates": [
{
"kind": "primary",
"literal": "relation \" \" does not exist",
"position": 0,
"role": "",
"template": "relation \"%s\" does not exist"
}
]
}runtimes · runtime.42P01-registry-final-20260909.latest · 18.6 (Homebrew) · passed
{
"cases": [
"missing_relation"
],
"limits": "",
"position": 0,
"raw": {
"cases": [
"missing_relation"
],
"id": "runtime.42P01-registry-final-20260909.latest",
"observed": {
"diagnostic": {
"message_primary": "relation \"c42p01_missing_relation.does_not_exist\" does not exist",
"severity": "ERROR",
"source_file": "parse_relation.c",
"source_function": "parserOpenTable",
"source_line": "1480",
"sqlstate": "42P01"
},
"statuses": {
"after_error": "IDLE",
"after_valid_query": "IDLE"
},
"valid_count": 0
},
"raw": "verify/results/42P01-registry-final-20260909/latest/raw.jsonl",
"raw_sha256": "c65e0596cb51d32791448e493b01de0bfda519bb35ed5d1153f07c156bd617ac",
"run_id": "42P01-registry-final-20260909",
"server_version": "18.6 (Homebrew)",
"server_version_num": 180006,
"snippet_registry": {
"path": "verify/cases/42P01/snippets.json",
"sha256": "f4eb28d6bc0d0d250d5dc548ed83a0783538eb73a07ab8b3670f218bcc21aba5"
},
"status": "passed",
"summary": "verify/results/42P01-registry-final-20260909/latest/summary.json",
"summary_sha256": "2b61950cb5a1a8f42fe130f2ad8407cb7cbaf4dfb396481fdf88d0d5769e3e37",
"target": "latest"
},
"run_id": "42P01-registry-final-20260909",
"runtime_id": "runtime.42P01-registry-final-20260909.latest",
"server_version": "18.6 (Homebrew)",
"status": "passed",
"target": "latest"
}runtimes · runtime.42P01-registry-final-20260909.pg10 · 10.21 (Debian 10.21-1.pgdg90+1) · passed
{
"cases": [
"missing_relation"
],
"limits": "",
"position": 1,
"raw": {
"cases": [
"missing_relation"
],
"id": "runtime.42P01-registry-final-20260909.pg10",
"image": "postgres@sha256:b2baf8998630663d21370da06387c950e587071bdd307ee34e661cdcc7442bcc",
"observed": {
"diagnostic": {
"message_primary": "relation \"c42p01_missing_relation.does_not_exist\" does not exist",
"severity": "ERROR",
"source_file": "parse_relation.c",
"source_function": "parserOpenTable",
"source_line": "1159",
"sqlstate": "42P01"
},
"statuses": {
"after_error": "IDLE",
"after_valid_query": "IDLE"
},
"valid_count": 0
},
"raw": "verify/results/42P01-registry-final-20260909/pg10/raw.jsonl",
"raw_sha256": "da4b4fcbbff2d04b8a03d0b7718cfe8b1954439f3bf3125cd8b79eaa88eeed79",
"run_id": "42P01-registry-final-20260909",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"server_version_num": 100021,
"snippet_registry": {
"path": "verify/cases/42P01/snippets.json",
"sha256": "f4eb28d6bc0d0d250d5dc548ed83a0783538eb73a07ab8b3670f218bcc21aba5"
},
"status": "passed",
"summary": "verify/results/42P01-registry-final-20260909/pg10/summary.json",
"summary_sha256": "3049254a6a818ed4401abdaee428fee0f17c4d6e299a4353e880ad6fe37a38d9",
"target": "pg10"
},
"run_id": "42P01-registry-final-20260909",
"runtime_id": "runtime.42P01-registry-final-20260909.pg10",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"status": "passed",
"target": "pg10"
}sources · src.errcodes.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "lines 372-378",
"path": "src/backend/utils/errcodes.txt",
"position": 0,
"sha256": "6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba",
"source_id": "src.errcodes.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt"
}sources · src.parse-relation.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "lines 1473-1501",
"path": "src/backend/parser/parse_relation.c",
"position": 1,
"sha256": "0d9c88f4a8def4c2d982c33f13208590e21ecf5e6f8cd9d7faa223dc771c9a9a",
"source_id": "src.parse-relation.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/parser/parse_relation.c#L1473-L1501"
}sources · src.namespace.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "lines 626-640",
"path": "src/backend/catalog/namespace.c",
"position": 2,
"sha256": "8c9e6a99e84fa2cec8a9b1de2ecbe3966a13f4ad68c6ccfbfb8134a754d73e56",
"source_id": "src.namespace.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/catalog/namespace.c#L626-L640"
}sources · doc.ddl.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "schemas, search_path, and namespace resolution",
"path": "doc/src/sgml/ddl.sgml",
"position": 3,
"sha256": "ce1919d9236f2e71672660e1a347146472e966e4d19b77fde5ae345dd1db6ec7",
"source_id": "doc.ddl.18.6",
"tag": "PG18-docs",
"url": "https://www.postgresql.org/docs/18/ddl-schemas.html"
}sources · doc.protocol.18
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "",
"location": "ErrorResponse fields",
"path": "doc/src/sgml/protocol.sgml",
"position": 4,
"sha256": "745339e07ebbc2bb67d98b258e25772ada644ef26011e3cd6b3fcbb435235f89",
"source_id": "doc.protocol.18",
"tag": "PG18-docs",
"url": "https://www.postgresql.org/docs/18/protocol-error-fields.html"
}sources · manifest.42P01
{
"commit": "",
"docs_url": "",
"kind": "local_artifact",
"location": "snapshots and definition_blobs entries for the 42P01 definition",
"path": "sources/manifest.lock.json",
"position": 5,
"sha256": "1727a275f336988ff96b4f9990a4ca253080f73fc5d316e7def165c8cf3708a8",
"source_id": "manifest.42P01",
"tag": "",
"url": "../sources/manifest.lock.json"
}sources · case-manifest.42P01
{
"commit": "",
"docs_url": "",
"kind": "local_artifact",
"location": "missing_relation",
"path": "verify/cases/42P01/cases.json",
"position": 6,
"sha256": "d0bd0702654b03dce66b733f5e4660b643db270682616c5927c9b10a12327088",
"source_id": "case-manifest.42P01",
"tag": "",
"url": "../verify/cases/42P01/cases.json"
}sources · snippet-registry.42P01.final
{
"commit": "",
"docs_url": "",
"kind": "local_artifact",
"location": "missing_relation ordered SQL",
"path": "verify/cases/42P01/snippets.json",
"position": 7,
"sha256": "f4eb28d6bc0d0d250d5dc548ed83a0783538eb73a07ab8b3670f218bcc21aba5",
"source_id": "snippet-registry.42P01.final",
"tag": "",
"url": "../verify/cases/42P01/snippets.json"
}Source references
Full definition and evidence JSON
Definition sources
center · PostgreSQL 18 · english-manuals:a4976e32bb384e78721bdb7f657a935e0d83939bf0999c6e8a2bd26708e5e407
Text language: en · english-manuals:a4976e32bb384e78721bdb7f657a935e0d83939bf0999c6e8a2bd26708e5e407