neondatabase/neon · error

cannot find 'blkno='

Error message

cannot find 'blkno='

What it means

SpanAttributesFromLogs::from_str requires both markers in the pasted log line: rel= (checked first) and blkno=. After rel= is found, a missing blkno= marker fails the parse. Like error 213, this also surfaces nested inside error 210's combined message.

Source

Thrown at pageserver/ctl/src/key.rs:259

}

#[derive(Debug)]
pub(super) struct SpanAttributesFromLogs(RelTag, BlockNumber);

impl std::str::FromStr for SpanAttributesFromLogs {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        // accept the span separator but do not require or fail if either is missing
        // "whatever{rel=1663/16389/24615 blkno=1052204 req_lsn=FFFFFFFF/FFFFFFFF}"
        let (_, reltag) = s
            .split_once("rel=")
            .ok_or_else(|| anyhow::anyhow!("cannot find 'rel='"))?;
        let reltag = reltag.split_whitespace().next().unwrap();

        let (_, blocknum) = s
            .split_once("blkno=")
            .ok_or_else(|| anyhow::anyhow!("cannot find 'blkno='"))?;
        let blocknum = blocknum.split_whitespace().next().unwrap();

        let reltag = reltag
            .parse()
            .with_context(|| format!("parse reltag from {reltag:?}"))?;
        let blocknum = blocknum
            .parse()
            .with_context(|| format!("parse blocknum from {blocknum:?}"))?;

        Ok(Self(reltag, blocknum))
    }
}

#[derive(Debug)]
#[allow(dead_code)] // debug print is used
enum RecognizedKeyKind {
    DbDir,
    ControlFile,

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Use a log line that also contains blkno=<number>, for example blkno=1052204.
  2. If the block number is known separately, use the multi-argument form: pageserver_ctl key 1663/16389/24615 1052204.

Example fix

# before
pageserver_ctl key "whatever{rel=1663/16389/24615}"
# -> "cannot find 'blkno='"

# after
pageserver_ctl key "whatever{rel=1663/16389/24615 blkno=1052204}"
Defensive patterns

Strategy: validation

Validate before calling

// both markers are required for the single-argument log-line form
anyhow::ensure!(
    line.contains("rel=") && line.contains("blkno="),
    "log line must contain both rel= and blkno="
);

Type guard

fn log_line_parseable(line: &str) -> bool {
    line.contains("rel=") && line.contains("blkno=")
}

Prevention

When it happens

Trigger: Passing a log line that contains rel=... but no blkno= marker, so no block number can be extracted.

Common situations: Pasting relation-only log lines; log levels or code paths that omit the block number attribute; trimmed log output.

Related errors


AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16). Data as JSON: /api/errors/312580090d2f3078. Report an issue: GitHub.