# 27000 — triggered_data_change_violation

> Source-backed reference for PostgreSQL SQLSTATE 27000, with explicit mechanism boundaries.
---

# 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.

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

| Field | Value |
| --- | --- |
| SQLSTATE | `27000` |
| Condition | `triggered_data_change_violation` |
| 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_TRIGGERED_DATA_CHANGE_VIOLATION` |
| Aliases | `—` |

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

## 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](../44000/) for a view invariant and [23514 check violation](../23514/) for a table constraint.

## Sources {#sources}

- [`src.errcodes.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt) (SHA-256 `6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba`)
- [`source path`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/commands/trigger.c#L3404-L3407) (SHA-256 `0a539af85b0de1a04779f92202e7bfc77d85ae6da1747ea32527c67f39084fbd`)
