Skip to content

44000 — with_check_option_violation

PostgreSQL SQLSTATE 44000: view WITH CHECK OPTION diagnostics and repair.

44000 — with_check_option_violation

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.

Field Value
SQLSTATE 44000
Condition with_check_option_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_WITH_CHECK_OPTION_VIOLATION
Aliases

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.

Compare 23514 check violation for a table CHECK and 27000 triggered data change violation for trigger-driven same-command changes.

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)