Skip to content

PVE spec: nested paths contain accumulated prefix segments — e.g. nodes/nodes/{node}/nodes/{node}/version instead of nodes/{node}/version #58

Description

@Liquidator2048

Summary

In artifacts/pve-specs/pve-api.json (and the YAML twin), every nested path key under paths is malformed: the full path-so-far is re-concatenated at every nesting level, instead of emitting
just the new segment. Top-level paths (/version, /nodes, /storage, /access, /cluster) are correct. Anything below them is broken.

The result is that any client driven by this spec calls bogus URLs and gets 404 from a real Proxmox VE node, even though the spec itself is OpenAPI-valid (parses fine, refs resolve, etc.).

Reproduction

Fetch the JSON spec and grep the paths object — many keys have repeated prefix chunks. Examples below taken verbatim from the current main branch.

Spec key (broken) Actual PVE endpoint
nodes/nodes/{node}/nodes/{node}/version nodes/{node}/version
cluster/cluster/config/cluster/config/apiversion cluster/config/apiversion
storage/storage/{storage} storage/{storage}
access/access/users/access/users/{userid}/access/users/{userid}/token/access/users/{userid}/token/{tokenid} access/users/{userid}/token/{tokenid}
nodes/nodes/{node}/nodes/{node}/qemu/nodes/{node}/qemu/{vmid}/nodes/{node}/qemu/{vmid}/status/nodes/{node}/qemu/{vmid}/status/start nodes/{node}/qemu/{vmid}/status/start
nodes/nodes/{node}/nodes/{node}/storage/nodes/{node}/storage/{storage}/nodes/{node}/storage/{storage}/content nodes/{node}/storage/{storage}/content

End-to-end test against a real PVE 9.1.9 node:

  • GET /api2/json/version200 OK (top-level path is correct in the spec)
  • GET /api2/json/nodes/<node>/version200 OK (the real endpoint exists)
  • GET /api2/json/nodes/nodes/<node>/nodes/<node>/version → would be 404 (the path the spec advertises does not exist on PVE)

Tested via a generic OpenAPI-driven HTTP client (rest-api-mcp) that loads the JSON spec, parses paths, and uses the keys verbatim as request paths. Top-level paths work; everything nested fails.

Pattern

The malformed key is the concatenation of every prefix from root to leaf, separated by /. Concretely, for the leaf endpoint nodes/{node}/qemu/{vmid}/status/start the spec emits:

nodes
+ / + nodes/{node}
+ / + nodes/{node}/qemu
+ / + nodes/{node}/qemu/{vmid}
+ / + nodes/{node}/qemu/{vmid}/status
+ / + nodes/{node}/qemu/{vmid}/status/start

i.e. nodes/nodes/{node}/nodes/{node}/qemu/nodes/{node}/qemu/{vmid}/nodes/{node}/qemu/{vmid}/status/nodes/{node}/qemu/{vmid}/status/start.

The canonical path is always the suffix starting at the last occurrence of the root segment. This holds uniformly across the sample I scanned (qemu, lxc, storage, access, cluster, ceph,
services, tasks, firewall, file-restore).

Likely cause

In the recursive walk that emits path keys (probably in scripts/unified_parser.py or one of the pve/ helpers), the recursion appears to pass the full path-so-far both as the key being
emitted and as the prefix for the next recursion level — so each child level receives parent_path + child_segment and emits parent_path + child_segment again, getting concatenated with the
next level. The fix is to emit only current_segment at each level (or equivalently, pass the segment list down and join once at the leaf).

Workaround for downstream users

While waiting for a fix, the spec can be salvaged client-side with a small post-processing step. For each key in paths:

def clean(p: str) -> str:
    segs = p.split("/")
    last = max(i for i, s in enumerate(segs) if s == segs[0])
    return "/".join(segs[last:])

This is idempotent on already-correct top-level keys and reconstructs the canonical path for every malformed nested key in the current spec.

Impact

The spec is currently unusable as a contract for any code-generated client or schema-driven tool against a real PVE node — only the handful of top-level endpoints work. Anyone consuming
pve-api.json / pve-api.yaml directly will hit 404 on essentially the entire API surface.

Environment

  • Spec source: https://raw.githubusercontent.com/basher83/Proxmox-OpenAPI/refs/heads/main/artifacts/pve-specs/pve-api.json (current main)
  • Target node: Proxmox VE 9.1.9 ({"repoid":"ee7bad0a3d1546c9","version":"9.1.9","release":"9.1"})
  • Auth used during reproduction: PVEAPIToken (no impact — auth path works, the URL path is wrong)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions