skip to content

In Django's system check framework, how do message levels and ids like security.W004 work, and what does SILENCED_SYSTEM_CHECKS suppress?

level: middleimportance: should knowfreq 35%

answer

  1. five levels, numeric like logging
  2. ERROR is where commands stop
  3. applabel dot letter plus number
  4. a list of ids in settings
  5. hidden and ignored, not fixed

basics

~20 s

Messages carry a level (Debug to Critical); Error and Critical stop management commands, lower levels are printed. Ids follow applabel.X001, where X marks the level. SILENCED_SYSTEM_CHECKS lists ids whose messages are hidden and excluded from the pass/fail decision.

solid answer

~40 s

Every check message has a numeric **level** — `DEBUG` 10, `INFO` 20, `WARNING` 30, `ERROR` 40, `CRITICAL` 50 — usually set through the `Debug`, `Info`, `Warning`, `Error` and `Critical` classes. Messages at `ERROR` or above are **serious**: commands that run checks stop with `SystemCheckError`, while warnings and below are printed and the command continues; `check --fail-level` moves that threshold for the `check` command only. The **id** is `applabel.` plus a level letter (`C`, `E`, `W`, `I`, `D`) and a number, so `security.W004` is a warning from the security checks (HSTS not configured). `SILENCED_SYSTEM_CHECKS`, empty by default, lists ids to acknowledge permanently: matching messages are not printed, are counted in the `(N silenced)` summary, and do not count toward failure. It works per id, project-wide, so it is a standing decision rather than a fix.

code

python · 5 lines
python
# settings/base.py
SILENCED_SYSTEM_CHECKS = [
    # Legacy one-to-one links are ForeignKey(unique=True); conversion is scheduled.
    "fields.W342",
]

go deeper

for a junior

Recall that Error and Critical stop commands, warnings are printed, and ids like security.W004 name each message so it can be looked up or silenced.

for a middle

Explain the numeric levels, the applabel.X000 id pattern, --fail-level, and exactly what silencing hides and excludes.

for a senior

Show discipline around the silence list: per-id, project-wide scope, comments and reviews, production-only entries, and never muting serious messages to ship.

for a principal

Treat silenced ids as recorded exceptions to policy, owned and revisited on each upgrade rather than accumulated.

## Levels `django.core.checks` defines five numeric levels, deliberately similar to Python's `logging` levels: | Constant | Value | Class | Effect in a command that runs checks | |---|---|---|---| | `DEBUG` | 10 | `Debug` | Printed | | `INFO` | 20 | `Info` | Printed | | `WARNING` | 30 | `Warning` | Printed; command continues | | `ERROR` | 40 | `Error` | `SystemCheckError`; command does not run | | `CRITICAL` | 50 | `Critical` | `SystemCheckError`; command does not run | A message is **serious** when its level is at or above the threshold, which is `ERROR` everywhere by default. The `check` command alone accepts `--fail-level CRITICAL|ERROR|WARNING|INFO|DEBUG` to move that threshold, which is how a pipeline makes warnings fatal. When something is reported, the output groups messages under `CRITICALS`, `ERRORS`, `WARNINGS`, `INFOS` and `DEBUGS` and goes to stderr. ## Ids Each message may carry an `id`. The documented pattern is **`applabel.X001`**: - `applabel` is the app or area that owns the check: `models`, `fields`, `urls`, `security`, `admin`, `auth`, `staticfiles`, or your own `shipping`. - `X` is the level letter: `C` critical, `E` error, `W` warning, `I` info, `D` debug. - The number is allocated by the owner and must be unique within that app. So `security.W004` is a warning from the security checks — it reports that `SECURE_HSTS_SECONDS` is not set while `SecurityMiddleware` is enabled, and it is a deployment check that only `check --deploy` runs. `fields.E300`-style ids come from field checks, `urls.W002`-style ids from URL checks. The full catalogue is the system check reference in the docs, and the id is what you search for when a message appears. A printed message reads `<object>: (<id>) <msg>`, followed by a `HINT:` line when a hint exists; the object prefix is the model label for model checks and `?` when there is no object. ## SILENCED_SYSTEM_CHECKS `SILENCED_SYSTEM_CHECKS` is a list of ids, default `[]`. For each message whose id is in the list: 1. It is **not printed**. 2. It is counted in the footer, as in `System check identified no issues (1 silenced).` 3. It is **excluded from the failure decision**, for `check --fail-level` and for the implicit checks before other commands. Some consequences worth knowing: - Silencing is **by id and project-wide**. You cannot silence `fields.W342` (`unique=True` on a `ForeignKey`) for one field only; every such field in the project goes quiet. - The documentation presents silencing as the way to acknowledge **warnings** you have inspected. Django's code filters silenced ids at every level, so listing an `Error` id also stops it blocking commands — which removes a safety net rather than fixing anything. - A message **without an id** cannot be silenced, which is one reason custom checks should always set one. - New Django releases add ids, and some ids disappear: `models.W042`, the auto-created primary key warning, was raised from 3.2 to 5.2 and is gone in 6.0, so an entry for it in a 6.1 project silences nothing. ## Reading one message Take a line such as `shop.Order.customer: (fields.W342) Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.` followed by a hint. Reading it left to right: 1. `shop.Order.customer` is the `obj` — the field at fault, printed before the id. 2. `fields` is the area that owns the check; `W` says it is a **warning**, so commands keep running. 3. `342` is the number the field checks allocated; together with the prefix it is the stable id. 4. The message and hint say what to change; the id is what you would add to `SILENCED_SYSTEM_CHECKS` if you decide to keep the design. ## Using levels well in your own checks - Reserve `Error` for configurations that will break at runtime; developers cannot start `runserver` until they fix it. - Use `Warning` for "probably wrong" and for conditions that differ legitimately between environments. - Pair an environment-sensitive rule with a `deploy=True` registration if it only matters in production. ## Silencing versus fixing Treat each silenced id as a small architectural decision: keep the list in version control, comment every entry with the reason, keep production-only silences in the production settings module, and revisit the list on upgrades.

  • Could you add an Error id to SILENCED_SYSTEM_CHECKS to unblock a deploy, and should you?
    Mechanically yes: Django excludes any silenced id from the failure decision, so the command would run. But an `Error` marks a configuration Django expects to break at runtime, and the docs present silencing as a way to acknowledge inspected warnings. Fix the cause, or narrow the rule in your own check, instead of muting a serious message project-wide.
  • How does check decide what goes to stdout and what goes to stderr?
    When unsilenced messages are reported but none reaches the fail level, `BaseCommand.check()` writes the report to stderr; when nothing visible is reported, the short `System check identified no issues (N silenced).` line from the `check` command goes to stdout. Serious messages at the fail level are raised as `SystemCheckError`, which the command line prints to stderr before exiting with status 1.

saying these in an interview costs you the question

  • SILENCED_SYSTEM_CHECKS silences a check for one chosen model only
  • A Warning stops management commands just like an Error
  • The letter in an id such as security.W004 is arbitrary
  • Silencing a message fixes the underlying configuration
  • Messages without an id can be silenced by their text