↑↓ select↵ open⌫ change scopeOpen full search

PG.CENTER connects PostgreSQL documentation, reference, and ecosystem knowledge. Maintained by Pigsty.

Wiki / SQLSTATE

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": %m when 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}

58P01, 58P03, 53100

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