{"record":{"id":"3e78f56b275bfd97","repo":"neondatabase/neon","slug":"found-no-reltag-in-arguments","errorCode":null,"errorMessage":"found no RelTag in arguments","messagePattern":"found no RelTag in arguments","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pageserver/ctl/src/key.rs","lineNumber":219,"sourceCode":"            more => {\n                // assume going left to right one of these is a reltag and then we find a blocknum\n                // this works, because we don't have plain numbers at least right after reltag in\n                // logs. for some definition of \"works\".\n\n                let Some((reltag_at, reltag)) = more\n                    .iter()\n                    .map(AsRef::as_ref)\n                    .enumerate()\n                    .find_map(|(i, s)| {\n                        s.split_once(\"rel=\")\n                            .map(|(_garbage, actual)| actual)\n                            .unwrap_or(s)\n                            .parse::<RelTag>()\n                            .ok()\n                            .map(|rt| (i, rt))\n                    })\n                else {\n                    anyhow::bail!(\"found no RelTag in arguments\");\n                };\n\n                let Some(blocknum) = more\n                    .iter()\n                    .map(AsRef::as_ref)\n                    .skip(reltag_at)\n                    .find_map(|s| {\n                        s.split_once(\"blkno=\")\n                            .map(|(_garbage, actual)| actual)\n                            .unwrap_or(s)\n                            .parse::<BlockNumber>()\n                            .ok()\n                    })\n                else {\n                    anyhow::bail!(\"found no blocknum in arguments\");\n                };\n\n                Ok(KeyMaterial::Split(reltag, blocknum))","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/pageserver/ctl/src/key.rs#L201-L237","documentation":"With two or more positional arguments, the key subcommand scans left to right for the first argument that parses as a RelTag (after stripping an optional rel= prefix). A RelTag looks like 1663/16389/24615 (tablespace/OID/database, optionally with a fork number). If no argument parses as a RelTag, the command bails.","triggerScenarios":"Multiple arguments where no element is a valid RelTag: only a block number and an LSN, or a reltag with non-numeric or missing components.","commonSituations":"Splitting a log line on whitespace and losing the rel= token; reltags with an unexpected fork suffix; hand-typed arguments with typos.","solutions":["Include the reltag as one argument, for example 1663/16389/24615 or rel=1663/16389/24615.","When copy-pasting from logs, keep the rel=... token intact; the parser strips the prefix itself."],"exampleFix":"# before\npageserver_ctl key 1052204 FFFF/FFFFFFFF\n# -> \"found no RelTag in arguments\"\n\n# after\npageserver_ctl key 1663/16389/24615 1052204","handlingStrategy":"validation","validationCode":"// ensure at least one argument parses as a RelTag (with optional rel= prefix)\nlet has_reltag = args.iter().any(|s| {\n    s.split_once(\"rel=\").map(|(_, v)| v).unwrap_or(s).parse::<RelTag>().is_ok()\n});\nanyhow::ensure!(has_reltag, \"no argument parses as a RelTag like 1663/16389/24615\");","typeGuard":"fn contains_reltag(args: &[String]) -> bool {\n    args.iter().any(|s| {\n        s.split_once(\"rel=\").map(|(_, v)| v).unwrap_or(s).parse::<RelTag>().is_ok()\n    })\n}","tryCatchPattern":null,"preventionTips":["Keep the rel=... token intact when copying from logs; the parser strips the prefix itself.","Pass the reltag as its own whitespace-separated argument."],"tags":["rust","neon","ctl","key-parsing","reltag"],"backgroundTag":"reltag-parse-failed","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}