{"record":{"id":"2347be95a38e3728","repo":"amir20/dozzle","slug":"invalid-group","errorCode":null,"errorMessage":"invalid group","messagePattern":"invalid group","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"internal/web/logs.go","lineNumber":345,"sourceCode":"\t\t\t}\n\t\t}\n\n\t\treturn len(labelFilters) > 0\n\t})\n}\n\nfunc (h *handler) streamGroupedLogs(w http.ResponseWriter, r *http.Request) {\n\tgroup := chi.URLParam(r, \"group\")\n\n\th.streamLogsForContainers(w, r, func(container *container.Container) bool {\n\t\treturn container.State == \"running\" && container.Group == group\n\t})\n}\n\nfunc (h *handler) streamHostGroupLogs(w http.ResponseWriter, r *http.Request) {\n\tgroup, err := url.PathUnescape(chi.URLParam(r, \"group\"))\n\tif err != nil || group == \"\" {\n\t\thttp.Error(w, \"invalid group\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\thostIDs := make(map[string]struct{})\n\tfor _, host := range h.hostService.Hosts() {\n\t\tif host.Group == group {\n\t\t\thostIDs[host.ID] = struct{}{}\n\t\t}\n\t}\n\n\th.streamLogsForContainers(w, r, func(c *container.Container) bool {\n\t\t_, ok := hostIDs[c.Host]\n\t\treturn c.State == \"running\" && ok\n\t})\n}\n\nfunc (h *handler) streamHostLogs(w http.ResponseWriter, r *http.Request) {\n\thost := hostKey(r)","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/amir20/dozzle/blob/d9463cbe21874e44ab79db6fa63e746ca7d22928/internal/web/logs.go#L327-L363","documentation":"streamHostGroupLogs reads the `group` URL parameter and unescapes it with url.PathUnescape. If the unescaping fails (malformed percent-encoding such as a stray `%`) or the result is empty, the handler rejects the request with \"invalid group\" and HTTP 400 Bad Request.","triggerScenarios":"GET /api/hosts/groups/{group}/logs/stream where group contains invalid percent-encoding like `%zz`, or the route is hit with an empty group segment. Both conditions map to this single 400 response.","commonSituations":"Client-side encodeURIComponent applied twice leaving raw `%` sequences; manually crafted URLs with truncated percent escapes; missing group path segment when building the URL programmatically; renamed groups while old bookmarks keep stale/empty paths.","solutions":["Pass a non-empty, correctly URL-encoded group name in the path (encodeURIComponent)","Remove any double encoding; encode once at URL construction","Check the group exists in host labels (dev.dozzle.group) before requesting its stream","Fix malformed `%` sequences in any hand-built URL"],"exampleFix":"// before\nconst url = `/api/hosts/groups/${group}/logs/stream`; // group contains '%' already encoded\n// after\nconst url = `/api/hosts/groups/${encodeURIComponent(group)}/logs/stream`;","handlingStrategy":"validation","validationCode":"if (!group || /%(?![0-9A-Fa-f]{2})/.test(group)) throw new Error(\"invalid group path parameter\");\nconst path = `/api/hosts/groups/${encodeURIComponent(group)}/logs/stream`;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Encode the group exactly once with encodeURIComponent","Verify group names against host dev.dozzle.group labels","Never build paths with raw user input containing %"],"tags":["http","url","bad-request","path-parameter"],"backgroundTag":"invalid-argument-format","analyzedSha":"d9463cbe21874e44ab79db6fa63e746ca7d22928","analyzedAt":"2026-09-07T10:08:55.855Z","contentChangedAt":"2026-09-07T10:08:55.855Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}