{"record":{"id":"4077e7356c52aca7","repo":"wavetermdev/waveterm","slug":"invalid-vdom-url-format","errorCode":null,"errorMessage":"Invalid VDOM URL format","messagePattern":"Invalid VDOM URL format","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"pkg/web/webvdomproto.go","lineNumber":24,"sourceCode":"import (\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/wavetermdev/waveterm/pkg/wshrpc\"\n\t\"github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient\"\n\t\"github.com/wavetermdev/waveterm/pkg/wshrpc/wshserver\"\n\t\"github.com/wavetermdev/waveterm/pkg/wshutil\"\n)\n\n// Add the new handler function\nfunc handleVDom(w http.ResponseWriter, r *http.Request) {\n\t// Extract UUID and path from URL\n\tpathParts := strings.Split(strings.TrimPrefix(r.URL.Path, \"/vdom/\"), \"/\")\n\tif len(pathParts) < 1 {\n\t\thttp.Error(w, \"Invalid VDOM URL format\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tuuid := pathParts[0]\n\t// Simple UUID validation\n\tif len(uuid) != 36 {\n\t\thttp.Error(w, \"Invalid UUID format\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// Reconstruct the remaining path\n\tpath := \"/\" + strings.Join(pathParts[1:], \"/\")\n\tif r.URL.RawQuery != \"\" {\n\t\tpath += \"?\" + r.URL.RawQuery\n\t}\n\n\t// Read request body if present\n\tvar body []byte","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/web/webvdomproto.go#L6-L42","documentation":"handleVDom in pkg/web/webvdomproto.go:24 rejects URLs that do not contain at least one path segment after the /vdom/ prefix. In practice strings.Split never returns fewer than 1 element, so this guard fires only for malformed routing setups where the request reaches the handler without a usable path. It returns HTTP 400.","triggerScenarios":"A request hits the /vdom/ route whose URL path, after trimming the prefix, yields no segments — e.g. a proxy or router rewrites the path away, or a misconfigured reverse proxy forwards an empty path to the vdom endpoint.","commonSituations":"Reverse-proxy strip-prefix rules (nginx 'proxy_pass' with trailing slash) consuming the UUID segment, a webserver route registered with a non-capturing pattern, or manually constructed fetch() calls to /vdom/ with no UUID.","solutions":["Check the request URL that reached the server; it must look like /vdom/<36-char-uuid>/<resource-path>.","Fix the reverse proxy or router config so the /vdom/ prefix and the UUID survive the rewrite.","Correct the client-side fetch/URL construction to include the UUID path segment.","Verify the handler registration in the web server routing table points at the right prefix."],"exampleFix":"// before (client)\nfetch(\"/vdom/\")\n\n// after\nfetch(`/vdom/${blockId}/render`) // blockId is a 36-char UUID","handlingStrategy":"validation","validationCode":"function validateVdomUrl(blockId, resourcePath) {\n  if (!blockId) throw new Error(\"vdom block id required\");\n  return `/vdom/${blockId}/${resourcePath.replace(/^\\//, \"\")}`;\n}","typeGuard":null,"tryCatchPattern":"const resp = await fetch(url);\nif (resp.status === 400) {\n  const msg = await resp.text();\n  throw new Error(`vdom request rejected: ${msg}`);\n}","preventionTips":["Always include the 36-char UUID as the first segment after /vdom/.","Audit reverse-proxy rewrite rules so the /vdom/ prefix and UUID are preserved.","Log the final request URL in debug mode before sending."],"tags":["go","http","url","bad-request"],"backgroundTag":"invalid-url-format","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}