loco-rs/loco · error

: : ` ` needs a reason — write it as ```rust ="why this is…

Error message

{}:{}: `{SKIP_MARKER}` needs a reason — write it as ```rust {SKIP_MARKER}="why this is not Rust"

What it means

The docs-syntax checker supports opting a Rust block out of checking by annotating the fence with a skip marker; this bail fires when the marker is present but carries no reason. The tool requires the reason attribute so that every opt-out is documented and auditable.

Solutions

  1. Change the fence to ```` ```rust skip="<reason>" ```` with a non-empty quoted reason
  2. Alternatively remove the skip marker entirely if the block is valid Rust and should be checked

Example fix

// before
```rust skip
let x = "not compilable";
```
// after
```rust skip="illustrative pseudo-code, not compilable"
let x = "not compilable";
```
Defensive patterns

Strategy: validation

Validate before calling

grep -rnE '^```rust\s+skip\s*$' docs/ && echo 'skip markers missing reasons'

Prevention

When it happens

Trigger: Writing ```` ```rust skip ```` (or with an empty/unparseable reason) in a docs markdown file, causing `reason_at` to return `None` when `collect` processes the file.

Common situations: Adding a skip marker in a hurry while fixing CI; copying an old-style marker without a quoted reason; forgetting the `="reason"` attribute.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of loco-rs/loco@23639d1e36 (2026-09-12). Data as JSON: /api/errors/b70d0a9657e4eb58. Report an issue: GitHub.

Appendix: source

Thrown at xtask/src/docs_syntax.rs:190

            "rs" => doc_comments_only(&fs::read_to_string(&path)?),
            _ => continue,
        };
        let lines: Vec<&str> = contents.lines().collect();
        let mut index = 0;
        while index < lines.len() {
            if !fence.is_match(lines[index]) {
                index += 1;
                continue;
            }
            let opened_at = index;
            // A bare `no-syntax-check` with no reason is rejected rather than
            // honoured — see the module docs.
            let skipped = match lines[opened_at].find(SKIP_MARKER) {
                None => false,
                Some(at) => {
                    let reason = reason_at(&lines[opened_at][at + SKIP_MARKER.len()..]);
                    if reason.is_none() {
                        bail!(
                            "{}:{}: `{SKIP_MARKER}` needs a reason — write it as \
                             ```rust {SKIP_MARKER}=\"why this is not Rust\"",
                            path.display(),
                            opened_at + 1
                        );
                    }
                    true
                }
            };
            index += 1;
            let start = index;
            while index < lines.len() && !closing.is_match(lines[index]) {
                index += 1;
            }
            if index >= lines.len() {
                bail!(
                    "{}:{}: ```rust block is never closed",
                    path.display(),

View on GitHub (pinned to 23639d1e36)