ruvnet/RuView · error · ValueError
{path}: each node needs 'id' and 'position_m' [x,y,z]
Error message
{path}: each node needs 'id' and 'position_m' [x,y,z] What it means
After load_geometry_file finds the nodes array, every element must be a JSON object containing at least 'id' and 'position_m' (a three-component [x, y, z] array in meters). The first node missing either key raises ValueError naming the offending file.
Source
Thrown at scripts/calibrate-camera-room.py:172
except ValueError:
print(" positions must be numeric", file=sys.stderr)
continue
nodes.append(node)
if not nodes:
print("WARNING: no transceiver nodes entered; bundle will carry empty geometry.",
file=sys.stderr)
return {"nodes": nodes, "units": "meters", "source": "tape-measure-prompt"}
def load_geometry_file(path: Path) -> dict:
with open(path, "r", encoding="utf-8") as f:
data = json.load(f)
nodes = data.get("nodes", data if isinstance(data, list) else None)
if nodes is None:
raise ValueError(f"{path}: expected {{'nodes': [...]}} or a top-level list")
for node in nodes:
if "id" not in node or "position_m" not in node:
raise ValueError(f"{path}: each node needs 'id' and 'position_m' [x,y,z]")
return {"nodes": nodes, "units": "meters", "source": "file"}
def main():
parser = argparse.ArgumentParser(
description="Two-checkerboard camera-room calibration (ADR-152 S2.1.3 / ADR-079)."
)
parser.add_argument("--wall-image", required=True,
help="Photo of the checkerboard on the origin wall")
parser.add_argument("--floor-image", required=True,
help="Photo of the checkerboard on the floor (camera NOT moved)")
parser.add_argument("--wall-origin", type=parse_vec3, default="0.5,0.0,1.6",
help="Room xyz (m) of the wall board's first inner corner "
"(default: 0.5,0.0,1.6)")
parser.add_argument("--floor-origin", type=parse_vec3, default="1.0,1.0,0.0",
help="Room xyz (m) of the floor board's first inner corner "
"(default: 1.0,1.0,0.0)")
parser.add_argument("--wall-axes", default="+x,-z",View on GitHub (pinned to 4685618388)
Solutions
- Rename keys to exactly 'id' and 'position_m' with a [x, y, z] array of meters
- Check every element — the loop raises on the first offender, so fix all
- If the file comes from another tool, write a small converter to the expected schema
Example fix
// before
{"nodes": [{"node_id": "n1", "xyz": [0, 0, 1]}]}
// after
{"nodes": [{"id": "n1", "position_m": [0.0, 0.0, 1.0]}]} Defensive patterns
Strategy: validation
Validate before calling
import json
def nodes_valid(path: str) -> bool:
with open(path, encoding="utf-8") as f:
data = json.load(f)
nodes = data.get("nodes", []) if isinstance(data, dict) else []
return bool(nodes) and all(
"id" in n and "position_m" in n
and isinstance(n["position_m"], list) and len(n["position_m"]) == 3
for n in nodes
) Try / catch
try:
geom = load_geometry_file(path)
except ValueError as e:
raise SystemExit(f"fix node entries (need 'id' + 'position_m' [x,y,z]): {e}") from e Prevention
- Use the same schema template for every node entry
- Write a linter/converter for files produced by other tools
- Include a sample node in the geometry file header or docs
When it happens
Trigger: A node entry like {"node_id": "n1", "xyz": [0,0,1]} (renamed keys), or positions expressed as separate x/y/z fields instead of one 'position_m' array.
Common situations: Schema drift between the tool that generated the geometry file and this script; manual editing that renames or restructures keys.
Related errors
- Calibration bundle {path} missing key {key!r}
- {path}: expected {{'nodes': [...]}} or a top-level list
- Intrinsics file {path} missing key {key!r}
- manifest must be an object with a 'markers' array
- Failed to load domain configuration: {e}
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/22cb2c186c0f16fe.
Report an issue: GitHub.