neondatabase/neon · error
failed to parse {one:?} as hex or span attributes: - {e1:#}
Error message
failed to parse {one:?} as hex or span attributes:
- {e1:#}
- {e2:#} What it means
With a single positional argument, the key subcommand tries two parsers in order: Key::from_hex (the fixed-width hexadecimal form of a key) and SpanAttributesFromLogs::from_str (a pasted log line containing rel= and blkno=). If both fail, this combined error reports both parse causes so you can see why neither form matched.
Source
Thrown at pageserver/ctl/src/key.rs:196
impl<S: AsRef<str>> TryFrom<&[S]> for KeyMaterial {
type Error = anyhow::Error;
fn try_from(value: &[S]) -> Result<Self, Self::Error> {
match value {
[] => anyhow::bail!(
"need 1..N positional arguments describing the key, try hex or a log line"
),
[one] => {
let one = one.as_ref();
let key = Key::from_hex(one).map(KeyMaterial::Hex);
let attrs = SpanAttributesFromLogs::from_str(one).map(KeyMaterial::String);
match (key, attrs) {
(Ok(key), _) => Ok(key),
(_, Ok(s)) => Ok(s),
(Err(e1), Err(e2)) => anyhow::bail!(
"failed to parse {one:?} as hex or span attributes:\n- {e1:#}\n- {e2:#}"
),
}
}
more => {
// assume going left to right one of these is a reltag and then we find a blocknum
// this works, because we don't have plain numbers at least right after reltag in
// logs. for some definition of "works".
let Some((reltag_at, reltag)) = more
.iter()
.map(AsRef::as_ref)
.enumerate()
.find_map(|(i, s)| {
s.split_once("rel=")
.map(|(_garbage, actual)| actual)
.unwrap_or(s)
.parse::<RelTag>()View on GitHub (pinned to 8f60b04da4)
Solutions
- Read both causes in the message: the first explains the hex failure, the second the log-line failure; fix whichever form you intended.
- For hex, paste the complete key string exactly as the pageserver prints it, not a prefix.
- For log lines, ensure both rel= and blkno= markers are present and their values well-formed.
Example fix
# before
pageserver_ctl key "000000067F00010001"
# -> failed to parse ... as hex or span attributes (both errors listed)
# after
pageserver_ctl key "000000067F000100010000AC0000000006"
# or paste the whole log line:
# pageserver_ctl key "whatever{rel=1663/16389/24615 blkno=1052204 req_lsn=FFFFFFFF/FFFFFFFF}" Defensive patterns
Strategy: validation
Validate before calling
// try the cheap, unambiguous forms first before relying on the ctl's combined parse
if let Ok(key) = Key::from_hex(arg) {
// unambiguous hex form
} else if arg.contains("rel=") && arg.contains("blkno=") {
// log-line form; let the ctl parse it
} else {
anyhow::bail!("argument is neither a hex key nor a log line with rel=/blkno=");
} Type guard
fn looks_like_key_material(s: &str) -> bool {
Key::from_hex(s).is_ok() || (s.contains("rel=") && s.contains("blkno="))
} Prevention
- Paste keys exactly as printed by the pageserver; do not truncate them.
- For log lines, verify both rel= and blkno= markers are present before invoking the ctl.
When it happens
Trigger: One argument that is neither a valid full-length hex key nor a log line with parseable rel= and blkno= fields; for example a truncated hex string, or a log line missing blkno.
Common situations: Copying only a prefix of a key from logs; pasting a log line whose rel= value is malformed; extra shell quoting that mangles the argument.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- need 1..N positional arguments describing the key, try hex o
- found no RelTag in arguments
- found no blocknum in arguments
- cannot find 'rel='
- cannot find 'blkno='
AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16).
Data as JSON: /api/errors/2ebdad815c33f178.
Report an issue: GitHub.