# 58P01 — undefined_file

> Source-backed full reference for PostgreSQL SQLSTATE 58P01.
---

# 58P01

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

`58P01` means that a required file or directory could not be found. In the fixed tablespace path, PostgreSQL distinguishes an `ENOENT` target during `chmod` from other permission or filesystem failures; the recovery hint is conditional on the server being in recovery.

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

| Field | Value |
| --- | --- |
| SQLSTATE | `58P01` |
| Condition | `undefined_file` |
| 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_UNDEFINED_FILE` |
| Aliases | `—` |

<!-- source facts: data/errcodes/58P01.json -->
<!-- END SQLSTATE FACTS -->

## Meaning {#meaning}

`utility.c` calls `PreventInTransactionBlock(isTopLevel, "CREATE TABLESPACE")` before entering `CreateTableSpace`, so the command is rejected inside an explicit transaction block; there is no explicit client transaction block to roll back for that command. `create_tablespace_directories()` is used after that command and from tablespace WAL replay. When the target is not an in-place directory and `chmod(location, ...)` returns `ENOENT`, the code emits SQLSTATE `58P01` with `directory "%s" does not exist`. It adds `Create this directory for the tablespace before restarting the server.` only when `InRecovery` is true. Other `chmod` failures use `errcode_for_file_access()` and the dynamic primary `could not set permissions on directory "%s": %m`; an in-place creation failure similarly uses `could not create directory "%s": %m` with an errno-selected code.

The condition is therefore broader than tablespace startup. The operation and `%m` detail decide whether the missing object is a tablespace, relation file, configuration file, or another file consumer.

## Messages {#messages}

- **ERROR**, SQLSTATE `58P01`: `directory "%s" does not exist`
  - Conditional hint during recovery: `Create this directory for the tablespace before restarting the server.`
- **ERROR**, with `errcode_for_file_access()`: `could not set permissions on directory "%s": %m`.
- **ERROR**, with `errcode_for_file_access()`: `could not create directory "%s": %m` (the in-place directory branch).

The latter two templates are not guaranteed to be `58P01`: `errcode_for_file_access()` selects the SQLSTATE from the saved errno.

## Diagnosis {#diagnosis}

Record the complete primary, `%m` detail, phase, path, database/tablespace identity, and whether the caller is SQL execution or WAL replay. Check that the expected volume is mounted at the exact path, then verify ownership, mode, symlink target, and the tablespace version directory. A missing mount and an intentionally removed directory need different recovery plans.

## Response {#response}

Restore the expected mount or directory from the deployment and backup procedure; do not create an arbitrary empty path over an unknown tablespace location. `CREATE TABLESPACE` is guarded by `PreventInTransactionBlock`, so it cannot run inside an explicit client transaction block; there is no explicit block to roll back for that command itself. If a different file consumer reports a client `ERROR` inside an explicit transaction, issue `ROLLBACK` or use an already-established savepoint before continuing. When the message comes from WAL recovery, there is no client transaction to resume: restore the path and follow the server's restart/recovery procedure. Retry only after ownership, permissions, and the target's contents have been checked.

## Versions {#versions}

The locked catalogue records this condition from 7.4; fixed source coverage is PostgreSQL 18.6. The cited source is a source-only review; no tablespace fault was induced.

## Related {#related}

[`58P02`](../58p02/), [`58P03`](../58p03/), [`58030`](../58030/)

## Sources {#sources}

[`src/backend/commands/tablespace.c#L347-L359`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/commands/tablespace.c#L347)

[`src/backend/commands/tablespace.c#L565-L625`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/commands/tablespace.c#L565)

[`src/backend/commands/tablespace.c#L1515-L1525`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/commands/tablespace.c#L1515)

[`src/backend/tcop/utility.c#L713-L717`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/tcop/utility.c#L713)

The structured [evidence record](../data/evidence/58p01.json) records conditional hints, dynamic errno paths, and the source/runtime boundary.
