Rules
Every rule has a code, a name and a category. Rules in the correctness category report queries the database rejects (or that fail at run time) and are errors by default; rules in the suspicious category report valid queries that almost certainly don't do what was meant, and are warnings by default. Rules in the restriction category ban constructs some codebases don't want and are off until you enable them. See Rules and levels to change their levels and Suppressing diagnostics for exceptions.
The E in a rule code is sqlsift's prefix, not a severity: a rule's level comes from its category and your configuration, so a warning can carry an E code too. Codes are assigned in order as rules are added and never change or get reused, so they are safe to keep in config files, suppression comments and baselines. Names are easier to read in config and comments; codes are shorter.
The examples on these pages use this schema:
CREATE TYPE order_status AS ENUM ('open', 'paid', 'shipped');
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
created_at TIMESTAMP NOT NULL DEFAULT now()
);
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id),
status order_status NOT NULL DEFAULT 'open',
total NUMERIC(10, 2) NOT NULL
);
CREATE TABLE coupons (
code TEXT PRIMARY KEY,
order_id INTEGER REFERENCES orders(id)
);
| Code | Name | Description |
|---|---|---|
| E0001 | table-not-found | Referenced table does not exist in schema |
| E0002 | column-not-found | Referenced column does not exist in table |
| E0003 | type-mismatch | Type incompatibility in expression |
| E0004 | potential-null-violation | Potential NOT NULL violation |
| E0005 | column-count-mismatch | Column count doesn't match (INSERT, column aliases, subqueries) |
| E0006 | ambiguous-column | Column reference is ambiguous across tables |
| E0007 | join-type-mismatch | JOIN condition compares incompatible types |
| E0008 | missing-required-column | INSERT omits a NOT NULL column without a default |
| E0009 | duplicate-name | Table alias or CTE name given twice in one query |
| E0010 | duplicate-target-column | Column given twice in an INSERT column list or UPDATE SET |
| E0011 | position-out-of-range | ORDER BY / GROUP BY position is not in the select list |
| E0012 | misplaced-aggregate | Aggregate or window function where it is not allowed |
| E0013 | generated-column-write | INSERT or UPDATE gives a value to a generated column |
| E0014 | unmatched-conflict-target | ON CONFLICT columns match no unique constraint |
| E0015 | distinct-order-by | SELECT DISTINCT ordered by a column it doesn't select |
| E0016 | grouping-error | Column must appear in GROUP BY or be used in an aggregate |
| E0017 | value-out-of-range | Literal too long or out of range for the column type |
| E0018 | null-comparison | Comparison with NULL using = or <> is never true |
| E0019 | not-in-with-nulls | NOT IN over a nullable subquery column |
| E0020 | outer-column-in-subquery | IN subquery selects a column of the outer query |
| E0021 | missing-join-condition | Tables in FROM with no condition linking them |
| E0022 | constant-condition | Condition that is always or never true from the schema |
| E0023 | outer-join-filtered | WHERE condition turns an outer join into an inner join |
| E0024 | unfiltered-write | UPDATE or DELETE without WHERE |
| E0025 | insert-without-columns | INSERT without a column list |
| E0026 | select-star | SELECT * in a query's result columns |
| E0027 | wrong-argument-type | Function or operator given an argument type it doesn't take |
| E0028 | limit-without-order-by | LIMIT or OFFSET without ORDER BY |
| E1000 | parse-error | SQL could not be parsed |