Linting

The [lint] section controls which diagnostics ubCode reports. Use it to suppress noisy warnings globally, override suppression for specific codes in the LSP, or target ignores to particular files or message patterns.

Minimal example

[lint]
ignore = ["block.title_line"]

[lint.per-file-ignores]
"tests/**/*.rst" = ["needs.dead_link"]

Core options

ignore

Type: array (default: [])

List of linting error codes to ignore globally across the project.

lsp_select

Type: array (default: [])

List of linting codes to specifically enable in Language Server Protocol (LSP) file diagnostics. This setting overrides the ignore list, allowing you to see specific errors in your editor even if they’re globally ignored.

[lint]
# List of linting codes to ignore
ignore = ["block.title_line"]
# A list of linting codes to select in LSP file diagnostics
# This overrides the ignore list.
lsp_select = ["block.title_line"]

Code matching and .* wildcards

Everywhere a list of diagnostic codes is configured — ignore, lsp_select, the code lists of per-file-ignores, and the codes scope of message-ignores — an entry matches a diagnostic in one of two ways:

  • Exactly: "needs.dead_link" matches only the needs.dead_link code.

  • As a family wildcard: a trailing .* matches a whole dot-namespaced family — "toctree.*" matches every toctree.<subcode> diagnostic, and also the bare family code itself (so "config.*" covers both the fine-grained config.<subcode> diagnostics and the plain config ones).

[lint]
# Suppress the whole std family — the dangling references
# (std.ref, std.doc, std.term) and the project-wide duplicates
# (std.duplicate_target, std.duplicate_label, std.duplicate_term)
# — plus one exact code.
ignore = ["std.*", "block.title_line"]

No other glob positions are supported: entries like "*.ref", "con*", or a bare "*" are treated as plain literals and match no real code.

A bare family name is not an umbrella: ignore = ["config"] matches only a diagnostic whose code is exactly config — it does not reach config.unknown_extension and its siblings. To suppress a whole family, use the .* wildcard.

Configuration diagnostics (config and config.*)

Problems found while resolving ubproject.toml itself are reported against the configuration file. The checks with a fine-grained code are individually suppressible:

  • config.unknown_extension — a [parse].extensions entry that looks like a typo of a known port name.

  • config.unknown_extension_option — a key other than active inside a [parse.extensions] entry table. The entry still switches its port; the key itself is ignored.

  • config.extension_always_on — a [parse].extensions entry switching off something built into ubCode (sphinx_needs), which stays active.

  • config.extension_unsupported — a [parse].extensions entry switching on an extension ubCode does not support (the sphinx.ext.autodoc family, sphinx.ext.graphviz); it runs only under sphinx-build.

  • config.invalid_extlink_template — a [parse.extlinks] entry with an invalid %s template.

  • config.extlink_shadows_builtin — a [parse.extlinks] role name that would shadow a built-in role.

  • config.extlinks_data_inert — a populated [parse.extlinks] table whose port is switched off in [parse].extensions, so none of its roles is registered. Most often an inherited = false meeting a child’s own table.

  • config.unknown_default_role — a [parse].default_role naming an unknown role.

  • config.conflicting_content_model — a directive registration whose body mode conflicts with a same-named built-in.

  • config.conflicting_directive_registration — two config entries that register the same directive name at runtime.

  • config.string_link_incomplete — a [needs.string_links] rule missing one of its four required keys.

  • config.string_link_regex_invalid — a string-link regex that does not compile (including one using look-ahead, look-behind or a backreference, which this engine does not support).

  • config.string_link_template_invalid — a string-link link_url or link_name that is not a valid template.

  • config.string_link_unknown_field — a string-link options entry naming a field the project never declared.

  • config.field_shadowed_by_identity — a project declares a field or link named content, on any of [needs.fields], [needs.links], extra_options or extra_links. content is the need’s own body, which no declaration can shadow. The declaration is kept, so nothing that renders today stops rendering — the option can still be set on a directive, and a link’s targets are still validated — but filters, tables, variant conditions, report templates and needs.json all answer the body for that name, so the declared value is invisible to every one of them. Rename the field or link; ignore silences the warning while you migrate. (id and type, the other two un-shadowable names, are refused outright and report under the plain config code.)

  • config.schema_unknown_key — a key in a schemas.json rule that neither ubCode nor sphinx-needs accepts, such as selct for select, propertes for properties, or a JSON-Schema keyword the rule grammar has no place for. Such a key used to be ignored, which silently changed what the rule meant: a misspelled select left the rule with no filter, so it applied to every need, and a misspelled key inside validate.local produced a rule that validated nothing at all. The message names the offending key, the rule and the keys accepted at that position. No rule from the file is applied while any such key remains, which is what sphinx-needs does too — it refuses to build at all.

  • config.schema_missing_validate — a schemas.json rule with no validate member. validate is what says what to check, so such a rule enforces nothing at all, which used to happen silently. sphinx-needs requires the member outright. A rule whose validate is present but empty is not reported — it asks for nothing and gets nothing, which is a rule doing what it says. No rule from the file is applied while the member is absent.

  • config.schema_invalid_value — a key in a schemas.json rule that both engines accept, whose value sphinx-needs constrains and ubCode found wrong: a type that is not "object" at a select, a validate.local or an allOf element, or not "array" on a network link block; a required that is not an array of strings; an unevaluatedProperties that is not a boolean; or a network link block that cannot be read at all (not an object, a contains or items that is not an object, a minContains or maxContains that is not an integer — any integer is accepted, whatever its sign or size, because that is all sphinx-needs requires, and a negative bound is applied when the rule runs rather than refused when it loads). The message names the key, the rule, the value found and the value expected. All four type positions used to be accepted silently. In a select or a validate.local ubCode ignores that value, so the check is for parity and clarity; inside an allOf element it is compiled verbatim, which is the costly case — "type": "string" makes the element match no need, so the rule enforces nothing. required and unevaluatedProperties used to be warnings whose constraint was then dropped, so the rule ran without it, and an unreadable network link block was dropped whole in silence. No rule from the file is applied while any such value remains; measured at sphinx-needs 8.4.0, sphinx-build aborts on each of the values listed here, and this code fires only where it does. Fix the value rather than ignoring the code: ignore silences the report but the file stays refused, so no rule from it is applied and ubc check then exits 0 on a project whose schema validation is switched off.

  • config.schema_sphinx_needs_incompatible — a schemas.json construct ubCode honours but sphinx-needs rejects, so sphinx-build fails on a file ubCode is happy with. In practice this is an extra keyword inside an allOf element, such as a not. The rule keeps working; only ignore it if the project never builds with sphinx-needs.

  • config.mount_invalid — a [[source.mounts]] entry whose mount_at, attach_to or entry_doc is not a relative document name, or whose files list is empty. The mount is dropped.

  • config.mount_unknown_key — a key on a mount entry that ubCode does not model. The key is ignored and the rest of the mount is honoured, so one ubproject.toml can be shared with sphinx-mounts.

  • config.mount_at_root — a mount with no mount_at, so it is mounted at the document root where any file it contributes can take the name of a host document.

  • config.mount_dead_option — a mount key its own mode never reads: include or exclude on a files mount (which has no walk to filter), or attach_each on a dir mount, without attach_to, or beside a non-default entry_doc.

  • config.mount_missing — a declared mount root that is not on disk. The mount contributes nothing this run and the pages it contributed on an earlier run are kept rather than reported as deleted.

  • config.mount_attach — a mount whose attach_to request could not be honoured: the host document does not exist, toctree_index is past the end of it, or the mount produced no document to attach. Not reported for a mount this variant gates off, which has nothing to attach by design.

  • config.mount_gated — a mount whose if gates it off for this variant, so it contributes no documents. Graded info, not warning: gating is what you asked for, and grading it a warning would fail ubc check on every build of every variant that gates anything. It is reported at all — and reported even when nothing in the project references the bundle — because a gated mount is otherwise a silent absence of a whole tree that may live in another repository.

  • config.mount_gated_contested — a gated mount that is not credited with the documents it removed, because at least one of them carries a name the build already uses. Toctree entries naming its pages then report toctree.nonexisting_document rather than the gate. Also graded info: it explains a warning that fires elsewhere rather than being one.

  • config.mount_invalid_condition — a mount whose if is not a valid condition. The mount is gated off, in every variant, until the condition is rewritten.

  • config.mount_condition_unevaluable — a mount whose if could not be evaluated against the variant data, an unknown var.* key being the common cause. The mount is gated off.

  • config.mount_excludes_root — a mount this variant gates off is the only root supplying [project] root_doc. This one refuses the whole configuration rather than reporting, so ignore does not reach it: nothing resolves. The same posture as config.variant_source_excludes_root below, and for the same reason.

  • config.variant_sources_sphinx_unsupported — a project declares a variant-gating key: [[source.variant_sources]] rules, or if on a [[source.mounts]] entry. sphinx-build reads either one only through sphinx-mounts at a release that supports it: without that, the two tools see different document sets. Graded info, not warning: it fires on every project that declares either key — ubCode cannot see what is installed on the Sphinx side, so it cannot tell you which case you are in — and grading it a warning would fail ubc check on a correctly configured project. ignore silences it once you have read it.

  • config.variant_source_unknown_key — a key on a variant_sources rule that ubCode does not model. Ignored, and the rest of the rule honoured, for the same shared-ubproject.toml reason as config.mount_unknown_key.

  • config.variant_source_invalid — a variant_sources rule with an empty files list. The rule is dropped, which is safe: it selected nothing.

  • config.variant_source_invalid_condition — a rule whose if is not a valid rule condition, or cannot be evaluated against the current variant data (an unknown var.* key is the usual cause). The rule’s files are excluded — warn-and-exclude, the same contract the if directive has. Silencing this code does not put the files back; it only hides the reason they are gone.

Two variant_sources problems are hard configuration errors rather than lint findings, so ignore does not reach them — nothing resolves, so nothing is linted:

  • config.variant_source_invalid_glob — a rule glob using {a,b} alternation or climbing out of the project with ... Refused rather than skipped: skipping the rule would leave every file it names in the build, including the files its other patterns name.

  • config.variant_source_excludes_root — a rule that is false for the current variant and would remove [project] root_doc. The message names the pattern to narrow.

All other configuration warnings (for example an unknown needs.global_options key) report under the plain config code.

[lint]
# Suppress just the typo check…
ignore = ["config.unknown_extension"]
# …or the whole configuration channel:
# ignore = ["config.*"]

Attention

Previously every configuration diagnostic reported under the single config code, so ignore = ["config"] suppressed the whole channel. The fine-grained codes are now the real lint codes, and a bare "config" entry matches only the code-less configuration warnings — replace it with "config.*" to keep suppressing everything.

Needs-domain diagnostics (needs.*)

Most needs.* codes are documented beside the directive or configuration key they concern. One is worth naming here, because it is the only one raised by a whole-PROJECT check rather than by reading a single file:

  • needs.cypher_vocabulary — a view directive’s :cypher: (Cypher query) references a label, relationship type or property key that does not exist anywhere in the project’s needs graph. openCypher runs such a query silently — the missing name reads as null, so the view usually matches nothing or renders blank cells, though a null-tolerant test such as IS NULL can instead make it match everything — and this is what says so, anchored on the :cypher: option, with the same did-you-mean notes ubc query cypher prints.

    Like every whole-project code (std.duplicate_docname, the toctree.* family), it is reported by ubc check, counted by the ubc build html quality gate, and listed — with its position — in the editor extension’s diagnostics view. It is not an inline squiggle: the editor’s per-file underlines carry the parse and markup phases only, which is why the needs.cypher_invalid on the very same option does underline and this one does not.

    One warning per directive, carrying every note its query produced, because a :cypher: has a single source range for the whole query:

    warning[needs.cypher_vocabulary]
      --> index.rst:9:5
      the needtable :cypher: query references vocabulary this project does not have: unknown label `ned` — did you mean `req`?; unknown property `staus` — did you mean `status`? (the query still runs — the missing name reads as null, so the result is not what the query says: usually no rows or blank cells, sometimes a full but wrong table)
    

    It is recomputed for the whole project on every index pass, so it disappears by itself once the missing vocabulary exists — you do not have to re-save the file it was raised on. A directive written in an .. include::``d fragment is reported against the FRAGMENT, with the including page named alongside it, so a ``per-file-ignores glob on either path suppresses it. A known field that merely happens to be unset on some needs never raises it: the check tests the project’s schema, never any need’s data.

    Narrow it with contains = "unknown label", scope it to a path with per-file-ignores ("index.rst" = ["needs.cypher_vocabulary"]), or silence the class with ignore = ["needs.cypher_vocabulary"]. message-ignores matches the message TEXT only, so a rule naming a position such as contains = "index.rst:9:5" never fires — use per-file-ignores for that. It is distinct from needs.cypher_invalid, which reports a query that does not parse or has the wrong shape — a different fault with a different fix, so the two are separately suppressible.

per-file-ignores

Type: object (default: {})

A mapping of glob patterns to lists of diagnostic codes. When a diagnostic’s source file matches a pattern, and the diagnostic code is in the associated list, the diagnostic is suppressed.

Paths are specified in POSIX format (forward slashes) and are relative to the configuration file directory, ensuring cross-platform compatibility. During configuration resolution, patterns are absolutised relative to the directory of the config file that defines them. This means patterns from an extend-ed parent config are correctly resolved relative to the parent’s location, not the child’s.

Standard glob syntax is supported (*, **, ?, [...]). Invalid glob patterns are reported as configuration diagnostics and skipped.

A diagnostic with multiple file-based source locations is suppressed if any of its file locations matches at least one rule for the code.

[lint.per-file-ignores]
# Ignore dead links and field validation errors in test fixtures
"tests/**/*.rst" = ["needs.dead_link", "needs.invalid_field_value"]
# Ignore schema violations in legacy documentation
"legacy/**" = ["needs.schema_definition_violation"]
# Ignore duplicate needs in a specific file
"docs/generated/index.rst" = ["needs.duplicate"]

message-ignores

Type: array of objects (default: [])

A list of rules for suppressing diagnostics whose message contains a given substring. Each rule is an object with:

  • codes (optional): a list of diagnostic codes this rule applies to. If omitted or empty, the rule applies to all diagnostic codes.

  • contains: a case-insensitive substring to match against the diagnostic message. If omitted or empty, the rule matches all messages for the specified codes (or all diagnostics if codes is also omitted).

This is useful for suppressing specific classes of validation errors, for example diagnostics about a known deprecated field.

# Suppress all diagnostics mentioning "deprecated_field"
[[lint.message-ignores]]
contains = "deprecated_field"

# Suppress only field validation errors mentioning a specific pattern
[[lint.message-ignores]]
codes = ["needs.invalid_field_value"]
contains = "legacy_option"

Source-mount confinement (build.mount_path_escape)

build.mount_path_escape reports a document contributed by a [[source.mounts]] tree that references a file outside that tree — an include, an image, a download or a diagram :file: that climbs out of the mount.

Despite the build. prefix it is an indexing diagnostic, anchored at the referring document, so unlike the ubc build html warnings below per-file-ignores does apply to it. That is the only way to hold two mounts to different policies, because ignore is project-wide per code:

[lint.per-file-ignores]
# Off for one trusted generated tree, still on for every other mount.
"generated/**" = ["build.mount_path_escape"]

# …or off for the whole project.
# [lint]
# ignore = ["build.mount_path_escape"]

Its severity is fixed at warning level. To make it fail a build, escalate with [build.html] denydeny = "warning" turns this (and every other warning) into a non-zero exit.

Files no root claims (std.file_outside_roots)

Added in version 0.33.0.

std.file_outside_roots reports a file that matches your source patterns but that no root claims: it lies outside the project’s source root ([source] dir, or the deprecated [project] srcdir) and outside every [[source.mounts]] root. The message names whichever of the two keys your project actually writes. Discovery walks the declared roots and nothing else, so such a file is not discovered at all — it is not indexed, it produces no page, and no :doc: or toctree entry can name it. This warning is the only thing that will tell you it is there.

It can only arise when the source root is an explicit subdirectory (or a directory beside the configuration folder): left unset, the source root is the configuration file’s own directory, which claims every file below it. For that default layout ubCode does not even look, so the check costs nothing.

Three ways to act on it, and they are what the message names:

  • move the file under the source directory (or under a mount root), which makes it a document;

  • add it to [source] extend_exclude, which stops discovering it — the right answer for a README.md sitting beside the project;

  • .. include:: it from a document, which is the right answer for a fragment. A file some document already pulls in this way is exempt and never reported: a fragment has no document name on purpose.

Use extend_exclude, not exclude. exclude is the base list, so setting it replaces the default hygiene patterns (.git, node_modules, _build, dist, .venv and the rest) — which would silence the file you named and start looking inside a vendored tree instead, earning a fresh std.file_outside_roots pointing inside it. extend_exclude adds to the defaults rather than replacing them.

The patterns this check honours are matched against the configuration folder — the tree it scans — rather than against a source root. That holds under [source] dir too, where the same patterns anchor at each source root for discovery: this pass walks the configuration folder, and a pattern compiled against a root that is not the tree being walked would exclude nothing here. It is the one place the configuration folder still decides anything once discovery follows the roots, and it is what makes a pattern you wrote to keep a directory out of your project keep it out of this report too.

Like build.mount_path_escape above it is an indexing diagnostic anchored at the file itself, so per-file-ignores applies — which is how one tree of loose files is silenced while the rest of the project stays covered:

[lint.per-file-ignores]
# Off for one directory of notes, still on everywhere else.
"notes/**" = ["std.file_outside_roots"]

# …or off for the whole project.
# [lint]
# ignore = ["std.file_outside_roots"]

Ignoring this code project-wide also skips the filesystem pass that feeds it. This check is a second, names-only walk of the configuration folder — it reads no file, but on a large repository it is not free — so a project that has silenced it stops paying for it as well. It is the one place a [lint] setting changes what ubCode reads from disk, and it is deliberate: a monorepo that does not want the check should not be charged for it on every build. per-file-ignores does not skip the pass, because a project that silences one directory still wants the report for the rest.

One class of file this check does not cover: a file under a mount root inside the configuration folder that the mount’s own walk does not yield. A mount claims its whole subtree, so such a file is “claimed” here even though nothing discovers it. Two things put a file in that state. The first is the mount’s own exclude — that absence is what your own mount configuration asked for, rather than something to warn you about. The second is a source or parser include pattern written with a directory prefix (vendor/*.rst): such a pattern is matched relative to the mount’s own root inside a mount, so it can stop matching there even though you named the file. If a file under a mount root has gone missing and you did not exclude it, check your include patterns for a directory prefix.

Its severity is fixed at warning level, and [build.html] deny escalates it like any other.

Variant-excluded toctree entries (toctree.variant_excluded)

Added in version 0.33.0.

toctree.variant_excluded reports a toctree entry naming a document that [[source.variant_sources]] removed from the current variant’s document set. The message names both the document and the if string that removed it, so the rule to narrow is the one you are told about.

It replaces two codes that would otherwise be misleading: toctree.nonexisting_document for an explicit entry (the name is not a mistake — the page exists in another variant), and toctree.empty_glob for a :glob: entry whose only matches were removed (the pattern is not empty — this variant emptied it).

It is graded info, not warning, and does not fail ubc check. In a 150% model a shared index that lists every edition’s pages is the normal shape, so this fires on configurations that are entirely correct — once per entry, on every build of every variant. As a warning it would have failed the default exit policy on such a project, and the obvious response would have been to ignore the code, which switches the reclassification off for the case it exists to catch: a rule glob that matched more than its author intended. Info keeps the message where you can read it and leaves the exit code alone.

Silencing it is therefore cosmetic rather than a way to unblock a build — it removes the message from the output, and nothing else:

[lint.per-file-ignores]
# Quieter for the one index that lists every edition's pages.
"reference/index.rst" = ["toctree.variant_excluded"]

# …or quiet for the whole project.
# [lint]
# ignore = ["toctree.variant_excluded"]

Consider leaving it on: it is the only remaining place a too-broad rule is visible, because a removed file is gone from every other product — no page, no document name, no needs, nothing in needs.json. If you want it enforced, [build.html] deny with deny = "info" escalates it like any other finding.

The diagnostic is anchored at the containing document, so per-file-ignores globs on the document that holds the toctree — not on the excluded page, which this variant does not have.

Ambiguous inventory matches (intersphinx.ambiguous)

intersphinx.ambiguous reports a cross-reference that matched more than one loaded intersphinx project — or more than one object type — after finding nothing in the project itself. It fires on :ref:, :term:, :doc:, :any:, a sphinx-design link typed any, and the unqualified :external: form; a target already qualified with a project key (:ref:`zulu:shared`, :external+zulu:ref:`shared`) names one inventory and cannot be ambiguous. The message says which project won and which also matched:

multiple inventory matches for 'shared': took 'zulu' (std:label), also matched by 'alpha' (std:label)

It is graded info, not warning, and never fails a build: the reference resolves, to exactly the page it always did, and a sphinx-build is silent about the collision entirely. Two overlapping inventories are also normal — every Sphinx-generated objects.inv ships the same handful of built-in labels — so this fires on configurations that are perfectly correct.

Read it as a note about your configuration rather than a fault in the page. It is worth reading because of how the winner is chosen: the inventories are merged in project-name order, and the alphabetically last project wins a collision. Adding an inventory whose key sorts after an existing one therefore moves every colliding link, silently — and so does renaming a project key. The order the projects appear in ubproject.toml has no effect.

To pin one target, qualify it with the project key:

:ref:`zulu:shared`
:external+zulu:ref:`shared`

To silence the notice instead:

[lint.per-file-ignores]
# Quiet for the one page that references the overlapping project.
"reference/api.rst" = ["intersphinx.ambiguous"]

# …or quiet for the whole project.
# [lint]
# ignore = ["intersphinx.ambiguous"]

If you want it enforced, [build.html] deny with deny = "info" escalates it like any other finding.

The equivalent collision reached through a Markdown link ([](#target) or [](inv:…)) reports intersphinx.ref at warning level instead, and fails a default build — because myst-parser warns on it and this side of the family follows its own upstream. The two codes are silenced separately.

Build warnings

Added in version 0.31.0.

The build.* warnings that ubc build html reports (build.directive_unhandled, build.search_index_large, and the rest) go through this same configuration: ignore suppresses one by code, and message-ignores narrows a code to particular messages — for instance a single unhandled directive name.

per-file-ignores does not apply to them: a build warning is a whole-build finding with no source file to match against.

Narrowing happens before gating: a code silenced here never reaches the quality gate that decides the exit code of ubc build html, so silencing a code is enough to keep a build green without lowering the project’s bar.

Changed in version 0.31.1: A warning belonging to one page now names it, as a docname: prefix on the message:

warning[build.video_glob_unsupported]
  guide/intro: a video source cannot be a wildcard pattern ...

The rest of the message is unchanged, so a message-ignores pattern written against the message text keeps matching, and you can narrow one to a single page by including the prefix (contains = "guide/intro: a video source").

This applies to the warnings raised while rendering a particular page. The unhandled-markup radars (build.directive_unhandled, build.role_unhandled) and the diagram-decline codes (build.diagram_file_unresolved, build.diagram_unconvertible, build.plantuml_render_failed) are also raised during rendering but are site-wide aggregates over every page, so they carry no prefix and name their example positions inside the message instead; nor do the whole-build warnings (asset reads, stale files, the manifest write), which belong to no page.

Two codes are the exception on the page-scoped side: build.need_view_failed and build.need_view_truncated name their own position as docname:line: (with the line number), so they are not given a second prefix — a narrowing pattern for either must use that form (contains = "guide/intro:42:"), not docname: plus a space.

Changed in version 0.31.2: build.need_view_truncated joins build.need_view_failed as a code that names its own docname:line: position. It is raised once per view directive whose :max_items: cap (its own, or the project-wide needs.views_max_items default) dropped items from the rendered result:

warning[build.need_view_truncated]
  index:16: view directive needlist #0 was truncated: showing the first 2 of 3 needs ...

Narrow it to one page the same way as its sibling — contains = "index:16:" — or silence the whole code with ignore = ["build.need_view_truncated"]. Like every build warning it counts toward the quality gate, so on the default bar a truncated view fails ubc build html until it is narrowed here or the cap is raised.

Added in version 0.31.2: build.need_style_invalid is raised once per need per page whose :style: carried a token that is not a valid CSS identifier (an ASCII letter or underscore, then ASCII letters, digits, underscores or hyphens) — so a need carded on two pages is reported for each. Such a token becomes no class on the card; valid tokens on the same need still apply:

warning[build.need_style_invalid]
  index: need REQ_1: ignored invalid :style: token(s) "9bad", "has space" ...

It is an ordinary page-scoped code — the message names the NEED and ubCode prefixes the page, so narrow it with contains = "index: need REQ_1" or silence the class with ignore = ["build.need_style_invalid"]. Like every build warning it counts toward the quality gate, so on the default bar a mistyped style fails ubc build html until it is fixed or narrowed here.

Added in version 0.31.2: build.need_layout_unknown is raised once per page and unknown name whose needs asked for a card design this project does not have — neither a built-in one nor one of its own [needs.card_layouts] designs. The affected needs are listed on the one line (the first five, then a count), because a mistyped [needs.fields.layout] default applies to every need in the project and would otherwise print hundreds of identical lines:

warning[build.need_layout_unknown]
  index: unknown :layout: "Focus" on 7 need(s) (REQ_1, REQ_2, REQ_3, REQ_4, REQ_5 and 2 more): rendered with the default layout "clean" (valid: clean, complete, focus, debug, clean_l, ...; aliases: test, focus_f)

The valid: list is built from your project: the built-in designs first, then any design [needs.card_layouts] defines, so a design you add appears in the message with no second edit. The named default is your project’s default_layout, so the message says which design the card actually got.

The card renders with the default clean design; a Sphinx-Needs build raises SphinxNeedLayoutException here, which ends the build. It is an ordinary page-scoped code — the message names the NEEDS and ubCode prefixes the page, so narrow it with contains = 'unknown :layout: "Focus"' or silence the class with ignore = ["build.need_layout_unknown"]. Like every build warning it counts toward the quality gate, so on the default bar a mistyped layout fails ubc build html until it is fixed or narrowed here.

Note

When using extend to inherit from a parent config, per-file-ignores and message-ignores use replace semantics: if the child config sets the field, it completely replaces the parent’s value (rather than merging additively). This is consistent with the behaviour of ignore and lsp_select. To combine parent and child rules, repeat the parent’s rules in the child config.

Deprecated since version 0.18.0: The rst_lint configuration section has been deprecated. Use lint instead for all linting configuration.