select open change scope Open full search

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

SQLSTATE / CLASS 44 · WITH CHECK OPTION VIOLATION

with_check_option_violation

SQLSTATE
44000
Condition name
with_check_option_violation
Class
WITH CHECK OPTION Violation
Source macro
ERRCODE_WITH_CHECK_OPTION_VIOLATION
Evidence
Observed at runtime in the source evidence
Analysis & operational context

English SQLSTATE atlas: authored explanations and source/runtime evidence are separate from the manual definitions. View source ↗

<h1>44000 — with_check_option_violation</h1>

At a glance

44000 means that a row written through a view would not satisfy that view's WITH CHECK OPTION predicate. It protects the view's write invariant; it is not the table-level CHECK condition 23514.

Meaning

When an automatically updatable view is defined with WITH CHECK OPTION, PostgreSQL checks that an inserted or updated row remains visible through the view. The executor treats both FALSE and NULL from the view predicate as failure, so a nullable predicate column does not make an unknown row pass. ExecWithCheckOptions reports new row violates check option for view "%s"; the dynamic failing-row DETAIL is included only when the permissions allow the row description. LOCAL checks conditions defined directly in the current view; underlying base-view conditions are not checked unless those base views also specify CHECK OPTION. CASCADED checks the current view and all underlying base-view conditions. CHECK OPTION is supported only on automatically updatable views without an INSTEAD OF trigger or rule; a trigger-updatable base view and an INSTEAD rewrite are separate boundaries where cascading or all checks can be ignored. The selected natural case is a directly updatable view.

Diagnosis

Capture SQLSTATE, view name, DETAIL when present, and the exact row values sent through the view. Read the definition with pg_get_viewdef() and evaluate its predicate using SQL three-valued logic: only TRUE is visible through the check option, while FALSE and NULL fail. Check whether the view is automatically updatable, whether it uses LOCAL or CASCADED, and whether a base view has an INSTEAD OF trigger or an INSTEAD rewrite. Do not search only for table CHECK constraints: LOCAL does not check ordinary underlying-view predicates, while CASCADED does unless a trigger-updatable or rewritten boundary prevents that cascade. Missing DETAIL can be a permission boundary rather than proof that no row was checked.

Response

Correct the row so its predicate is TRUE, or change the view definition only after confirming the schema contract and the intended LOCAL/CASCADED scope. Keep the check option when the view is meant to be an enforced filtered interface. If a trigger-updatable base view or an INSTEAD rewrite is involved, inspect that boundary and its effective checks; do not assume a cascaded check reached it. After an autocommit error the selected connection remained IDLE; inside an explicit transaction rollback the failed block before retrying with a valid row.

Messages

The fixed source templates are new row violates check option for view "%s" and Failing row contains %s.. The view identifier and row rendering are dynamic. Treat DETAIL as diagnostic data and avoid copying it into a stable parser without accounting for values and formatting.

Representative case

The shared registry in verify/cases/44000/snippets.json (SHA-256 7b227bca904c860388c6cf1f5b7f551412b4d67832fb91aaa682f4126072e41c) creates a filtered view, attempts one row outside the predicate, and then inserts a valid row. See the public case export and structured evidence.

CREATE TABLE items(id integer PRIMARY KEY, visible boolean NOT NULL, note text NOT NULL);
CREATE VIEW visible_items AS SELECT id, visible, note FROM items WHERE visible WITH CHECK OPTION;
INSERT INTO visible_items VALUES (1, false, 'hidden');
INSERT INTO visible_items VALUES (1, true, 'visible');
SELECT id, visible, note FROM visible_items ORDER BY id;

The runner qualifies registry relation names inside a private schema. It asserts the natural server SQLSTATE and view diagnostic, then verifies that only the visible row was accepted.

The selected case observed 44000 on PostgreSQL 18.6 and 10.21 when a row with visible = false was inserted through a view with WITH CHECK OPTION. The DETAIL contained the failing row, autocommit stayed IDLE, and a row satisfying the predicate was accepted.

Versions

The locked catalogue records this condition from the early historical boundary through the formal snapshots. The fixed source has the same mechanism in 18.6 and 10.23; the selected runtime case covers a simple insert through a view on 18.6 and 10.21, not every view-rule composition.

Sources

  • src.errcodes.18.6 (SHA-256 6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba)
  • src.execMain.18.6 (SHA-256 33b97337fa23a649c5e7a092e1bd405a54e8503529236c62c9d5bb93a1774a8d)
  • CREATE VIEW documentation · local call scan src.calls.REL_18_6 (SHA-256 9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf)

Source evidence

Evidence belongs to the frozen source and runtime versions listed here. It is not a runtime verification of the selected manual version.

44000 is the with_check_option_violation condition in Class 44.

Method: Read the fixed errcodes.txt row and macro mapping.

Limits: This is a view write invariant, not a table CHECK constraint code.

src.errcodes.18.6

ExecWithCheckOptions emits new row violates check option for view "%s" with a dynamic failing-row DETAIL.

Method: Trace ERRCODE_WITH_CHECK_OPTION_VIOLATION in execMain.c.

Limits: The row representation and view name are dynamic.

src.execMain.18.6 src.calls.REL_18_6

ExecWithCheckOptions treats a view check qual that evaluates to NULL or FALSE as a violation because the new tuple would not be visible through the view.

Method: Read the fixed ExecWithCheckOptions comment and branch before the ERRCODE_WITH_CHECK_OPTION_VIOLATION report.

Limits: This describes the executor check; the selected case uses a directly updatable view.

src.execMain.18.6

The failing-row DETAIL for a view check option is conditional on permissions that allow the row description.

Method: Trace the WCO_VIEW_CHECK permission guard before ExecBuildSlotValueDescription.

Limits: DETAIL may be absent even when the check ran.

src.execMain.18.6

LOCAL checks only conditions defined directly in the current view; ordinary underlying-view conditions are not checked unless those base views also specify CHECK OPTION. CASCADED checks the current view and all underlying base-view conditions. CHECK OPTION is supported only on automatically updatable views without an INSTEAD OF trigger or rule; a trigger-updatable base view stops a cascade, and an INSTEAD rule rewrite can cause all checks to be ignored.

Method: Read the fixed CREATE VIEW documentation and compare the selected case definition.

Limits: The selected runtime case is a direct automatically updatable view; it does not exercise nested views, a trigger-updatable base, or an INSTEAD rewrite.

doc.create-view.18.6

A write through a view with WITH CHECK OPTION must satisfy the view predicate; correcting the row preserves the invariant.

Method: Use the shared visible=true/false view case.

Limits: LOCAL/CASCADED view composition and UPDATE paths can add further predicates.

doc.create-view.18.6

The selected 44000 case passed on PostgreSQL 18.6 and 10.21 with the structured SQLSTATE, transaction-state, and repair assertions recorded in the runtime entries.

Method: Read the selected runner summaries and raw outputs tied to the shared snippet registry.

Limits: This covers the selected directly updatable view path; it does not test nested LOCAL/CASCADED views or INSTEAD OF triggers.

runtime.44000-batch34-20260909.latest runtime.44000-batch34-20260909.pg10

Message templates

ERROR · message.view-check

Primary

new row violates check option for view "%s"

Detail

Failing row contains %s.

Both the view identifier and row rendering are dynamic.

Reproduction & repair cases

view_check_option_recovery · PG 10, 18

Preconditions

  • A runner-owned disposable target is provisioned.

Trigger: Insert a row through a view with a visible-row predicate and WITH CHECK OPTION, then insert a row satisfying the predicate.

Expected assertions

  • SQLSTATE is 44000
  • The diagnostic identifies the view
  • The rejected row leaves autocommit usable
  • A row satisfying the view predicate is accepted

Repair: Fix the row or the view predicate deliberately; do not bypass the view invariant by treating this as a table constraint failure.

Cleanup: Drop the case schema with an owner connection.

Recorded runtime evidence

18.6 (Homebrew) · passed

Run: 44000-batch34-20260909

{
  "repair": {
    "rows": [
      [
        1,
        true,
        "visible"
      ]
    ]
  },
  "primary": "new row violates check option for view \"visible_items\"",
  "severity": "ERROR",
  "sqlstate": "44000",
  "statuses": {
    "after_error": "IDLE",
    "after_valid": "IDLE"
  },
  "connection_autocommit": true
}
10.21 (Debian 10.21-1.pgdg90+1) · passed

Run: 44000-batch34-20260909

{
  "repair": {
    "rows": [
      [
        1,
        true,
        "visible"
      ]
    ]
  },
  "primary": "new row violates check option for view \"visible_items\"",
  "severity": "ERROR",
  "sqlstate": "44000",
  "statuses": {
    "after_error": "IDLE",
    "after_valid": "IDLE"
  },
  "connection_autocommit": true
}

Definition snapshot: english-manuals:66e9053078b204dcd064a8b43dd… · English manual source