↑↓ select↵ open⌫ change scopeOpen full search

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

Wiki / SQLSTATE

27000 — triggered_data_change_violation

27000 is a source-confirmed trigger-protection condition. PostgreSQL raises it when a row has already been changed by an operation triggered by the current command; the fixed 18.6 source hint points toward using an AFTER trigger when the intent is to propagate changes to other rows. A naive self-updating BEFORE trigger can recurse or alter the trigger semantics, so this entry does not present it as a safe generic reproduction.

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
Triggered Data Change Violation
condition name
triggered_data_change_violation
lang
en
sqlstate
27000

Definition PG 18

27000 — triggered_data_change_violation

At a glance {#at-a-glance}

27000 is a source-confirmed trigger-protection condition. PostgreSQL raises it when a row has already been changed by an operation triggered by the current command; the fixed 18.6 source hint points toward using an AFTER trigger when the intent is to propagate changes to other rows. A naive self-updating BEFORE trigger can recurse or alter the trigger semantics, so this entry does not present it as a safe generic reproduction.

Meaning {#meaning}

27000 is the trigger data change violation raised by the executor when a tuple has already been modified by an operation triggered by the current command. The fixed trigger.c path is specifically a same-command, same-tuple guard for a trigger-driven change; it is not a label for every trigger exception or recursive trigger.

Diagnosis {#diagnosis}

Start with the target relation, the statement's affected row, and the BEFORE row triggers that can update that row. The fixed primary template is tuple to be updated was already modified by an operation triggered by the current command, with a hint to consider an AFTER trigger for propagating changes to other rows. A self-update test that merely recurses is a different failure and does not establish this path. This batch has no natural runtime observation, so record the actual transaction state from the client if a real trigger error occurs.

Response {#response}

If the trigger is propagating a change to another row, an AFTER trigger or one set-based statement may fit the intended semantics; redesign the trigger when the same tuple is legitimately targeted twice. Do not respond with a generic retry or CASCADE, and do not claim that rolling back a fabricated self-update reproduces 27000. Roll back a genuinely failed explicit transaction before issuing repair SQL.

Versions {#versions}

The locked facts table records catalogue presence across the project snapshot range. The fixed source evidence is limited to the path stated below; no exact behavioral introduction or broader runtime coverage is inferred from the definition alone.

Related {#related}

Compare 44000 WITH CHECK OPTION violation for a view invariant and 23514 check violation for a table constraint.

Sources {#sources}

  • src.errcodes.18.6 (SHA-256 6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba)
  • source path (SHA-256 0a539af85b0de1a04779f92202e7bfc77d85ae6da1747ea32527c67f39084fbd)

Compare versions

SQLSTATE evidence and recorded runtime versions

cases · triggered_data_change_boundary
{
  "assertions": [],
  "case_id": "triggered_data_change_boundary",
  "cleanup": "Drop the case schema with an owner connection.",
  "has_snippet": false,
  "position": 0,
  "preconditions": [
    "A runner-owned disposable target is provisioned."
  ],
  "repair": "Use the source-confirmed trigger design and test it separately when the application can control the affected-row semantics.",
  "trigger": "No artificial trigger is executed; the page records the fixed source path and its safe-case boundary.",
  "versions": [
    "10",
    "18"
  ]
}
claims · identity
{
  "claim_id": "identity",
  "limits": "This records the protocol definition and does not imply a natural PostgreSQL throw path.",
  "method": "Read the fixed errcodes.txt row and macro mapping.",
  "position": 0,
  "runtime": [],
  "sources": [
    "src.errcodes.18.6"
  ],
  "statement": "27000 is the triggered_data_change_violation condition in Class 27."
}
claims · source-boundary
{
  "claim_id": "source-boundary",
  "limits": "No representative runtime case is claimed; the path requires a specialized internal or trigger/procedure context.",
  "method": "Trace the fixed source call scan and classify the path before selecting a safe runner case.",
  "position": 1,
  "runtime": [],
  "sources": [
    "src.trigger.18.6",
    "src.calls.REL_18_6"
  ],
  "statement": "tuple to be updated was already modified by an operation triggered by the current command is a source-confirmed path for 27000."
}
messages · message.triggered-data-change
{
  "limits": "The hint and any row identity are contextual; this is the fixed BEFORE-trigger same-tuple branch.",
  "message_id": "message.triggered-data-change",
  "path": "",
  "position": 0,
  "raw": {
    "id": "message.triggered-data-change",
    "limits": "The hint and any row identity are contextual; this is the fixed BEFORE-trigger same-tuple branch.",
    "primary_template": "tuple to be updated was already modified by an operation triggered by the current command",
    "severity_source": "ERROR",
    "sources": [
      "src.trigger.18.6"
    ],
    "sqlstate": "27000"
  },
  "severity": "ERROR",
  "sources": [
    "src.trigger.18.6"
  ],
  "templates": [
    {
      "kind": "primary",
      "literal": "tuple to be updated was already modified by an operation triggered by the current command",
      "position": 0,
      "role": "",
      "template": "tuple to be updated was already modified by an operation triggered by the current command"
    }
  ]
}
messages · message.triggered-data-change-hint
{
  "limits": "The hint describes this source branch and is not a universal trigger migration rule.",
  "message_id": "message.triggered-data-change-hint",
  "path": "",
  "position": 1,
  "raw": {
    "hint_template": "Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.",
    "id": "message.triggered-data-change-hint",
    "limits": "The hint describes this source branch and is not a universal trigger migration rule.",
    "severity_source": "ERROR",
    "sources": [
      "src.trigger.18.6"
    ],
    "sqlstate": "27000"
  },
  "severity": "ERROR",
  "sources": [
    "src.trigger.18.6"
  ],
  "templates": [
    {
      "kind": "hint",
      "literal": "Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.",
      "position": 0,
      "role": "",
      "template": "Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows."
    }
  ]
}
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"
}
sources · src.calls.REL_18_6
{
  "commit": "",
  "docs_url": "",
  "kind": "local_artifact",
  "location": "",
  "path": "raw/calls/REL_18_6.jsonl",
  "position": 1,
  "sha256": "9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf",
  "source_id": "src.calls.REL_18_6",
  "tag": "",
  "url": ""
}
sources · src.trigger.18.6
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "",
  "kind": "upstream_source",
  "location": "",
  "path": "src/backend/commands/trigger.c",
  "position": 2,
  "sha256": "0a539af85b0de1a04779f92202e7bfc77d85ae6da1747ea32527c67f39084fbd",
  "source_id": "src.trigger.18.6",
  "tag": "REL_18_6",
  "url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/commands/trigger.c#L3404-L3407"
}

Source references

Full definition and evidence JSON

Definition sources

center · PostgreSQL 18 · english-manuals:67f7917e6f8a1e33fb5bf8cabb0e64c872c4782d3fc5e2088b8288cac3ebec7d

Text language: en · english-manuals:67f7917e6f8a1e33fb5bf8cabb0e64c872c4782d3fc5e2088b8288cac3ebec7d