58P02 — duplicate_file
58P02 is the duplicate-file condition in the fixed server-side base-backup output path. The path accepts a missing directory, accepts an existing empty directory, and raises this code when the existing target is non-empty.
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
- System Error (errors external to PostgreSQL itself)
- condition name
- duplicate_file
- lang
- en
- sqlstate
- 58P02
Definition PG 18
58P02
At a glance {#at-a-glance}
58P02 is the duplicate-file condition in the fixed server-side base-backup output path. The path accepts a missing directory, accepts an existing empty directory, and raises this code when the existing target is non-empty.
Meaning {#meaning}
bbsink_server_new() first performs and commits its privilege check transaction. It then rejects relative paths and calls pg_check_dir(pathname): result 0 creates the directory, result 1 accepts an empty directory, and results 2–4 enter the fixed ERRCODE_DUPLICATE_FILE branch. An access error takes a separate errcode_for_file_access() branch. This is a base-backup output safety check, not proof that every EEXIST or non-empty directory in PostgreSQL uses 58P02.
Messages {#messages}
- ERROR, SQLSTATE
58P02:directory "%s" exists but is not empty. - ERROR, with
errcode_for_file_access():could not access directory "%s": %m. - ERROR, with
errcode_for_file_access():could not create directory "%s": %mwhen the target is absent but creation fails.
The last two templates receive their SQLSTATE from the saved OS errno and should not be relabeled 58P02 merely because they occur in the same function.
Diagnosis {#diagnosis}
Confirm that the path is the intended base-backup destination, inspect its owner, mount, and inventory, and determine whether it contains a prior complete backup or an interrupted one. Preserve that inventory before changing it. The source path performs output preparation after the internal privilege-check transaction has been committed, so this condition is a failed backup setup rather than evidence that a user DML transaction can be repaired by blindly continuing.
Response {#response}
Use a documented empty destination or archive the previous output according to the backup policy. Validate the completed backup and its manifest after creation; never recursively delete or force-overwrite an unknown directory. If an outer client command reports an ERROR, follow the actual session state and roll back to an existing savepoint or transaction as appropriate, but do not treat ROLLBACK as a way to make the non-empty backup target safe. A new connection is needed only if the owning server process was terminated.
Versions {#versions}
The locked catalogue records this condition from 7.4; the fixed base-backup path is from PostgreSQL 18.6. No backup target was altered or tested for this source-only entry.
Related {#related}
Sources {#sources}
src/backend/backup/basebackup_server.c#L59-L125
The structured evidence record records the directory-state branches, dynamic errno paths, and source/runtime boundary.
Compare versions
SQLSTATE evidence and recorded runtime versions
claims · identity
{
"claim_id": "identity",
"limits": "",
"method": "Read locked definition snapshot.",
"position": 0,
"runtime": [],
"sources": [
"src.errcodes.18.6"
],
"statement": "58P02 is duplicate_file in SQLSTATE Class 58."
}claims · resolved-paths
{
"claim_id": "resolved-paths",
"limits": "Source confirmation is not natural runtime.",
"method": "Read the complete sink constructor and directory-state switch.",
"position": 1,
"runtime": [],
"sources": [
"src.path.0"
],
"statement": "The server-side base-backup sink commits its privilege-check transaction before checking the output directory, accepts empty targets, and emits 58P02 only for an existing non-empty target; other branches use errno-selected codes."
}claims · history
{
"claim_id": "history",
"limits": "",
"method": "Use locked catalogue boundary.",
"position": 2,
"runtime": [],
"sources": [
"src.errcodes.18.6"
],
"statement": "The locked catalogue records 58P02 from 7.4; it does not prove every historical duplicate-file caller."
}messages · message.0
{
"limits": "",
"message_id": "message.0",
"path": "",
"position": 0,
"raw": {
"id": "message.0",
"primary_template": "directory \"%s\" exists but is not empty",
"severity_source": "ERROR",
"sources": [
"src.path.0"
],
"sqlstate": "58P02"
},
"severity": "ERROR",
"sources": [
"src.path.0"
],
"templates": [
{
"kind": "primary",
"literal": "directory \" \" exists but is not empty",
"position": 0,
"role": "",
"template": "directory \"%s\" exists but is not empty"
}
]
}messages · message.1
{
"limits": "",
"message_id": "message.1",
"path": "",
"position": 1,
"raw": {
"code_selection": "errcode_for_file_access()",
"id": "message.1",
"primary_template": "could not access directory \"%s\": %m",
"severity_source": "ERROR",
"sources": [
"src.path.0"
],
"sqlstate": "58P02"
},
"severity": "ERROR",
"sources": [
"src.path.0"
],
"templates": [
{
"kind": "primary",
"literal": "could not access directory \" \":",
"position": 0,
"role": "",
"template": "could not access directory \"%s\": %m"
}
]
}messages · message.2
{
"limits": "",
"message_id": "message.2",
"path": "",
"position": 2,
"raw": {
"code_selection": "errcode_for_file_access()",
"id": "message.2",
"primary_template": "could not create directory \"%s\": %m",
"severity_source": "ERROR",
"sources": [
"src.path.0"
],
"sqlstate": "58P02"
},
"severity": "ERROR",
"sources": [
"src.path.0"
],
"templates": [
{
"kind": "primary",
"literal": "could not create directory \" \":",
"position": 0,
"role": "",
"template": "could not create directory \"%s\": %m"
}
]
}sources · src.errcodes.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"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#L447"
}sources · src.path.0
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/backup/basebackup_server.c",
"position": 1,
"sha256": "1447d7223926f903d27744605f9caec8a610d78a9f7a7864bb3afb6b3073ac19",
"source_id": "src.path.0",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/backup/basebackup_server.c#L59"
}Source references
Full definition and evidence JSON
Definition sources
center · PostgreSQL 18 · english-manuals:9e350d7653c989a2faae19e2a4a72bac8a5882a494b89cb1c3c910efa990a41f
Text language: en · english-manuals:9e350d7653c989a2faae19e2a4a72bac8a5882a494b89cb1c3c910efa990a41f