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

  1. Rename keys to exactly 'id' and 'position_m' with a [x, y, z] array of meters
  2. Check every element — the loop raises on the first offender, so fix all
  3. 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

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


AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16). Data as JSON: /api/errors/22cb2c186c0f16fe. Report an issue: GitHub.