{"record":{"id":"97f1968823ea7022","repo":"vxcontrol/pentagi","slug":"containers-invalidrequest","errorCode":"Containers.InvalidRequest","errorMessage":"group field not found","messagePattern":"group field not found","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"backend/pkg/server/services/containers.go","lineNumber":101,"sourceCode":"\t\t}\n\t} else if slices.Contains(privs, \"containers.view\") {\n\t\tscope = func(db *gorm.DB) *gorm.DB {\n\t\t\treturn db.\n\t\t\t\tJoins(\"INNER JOIN flows f ON f.id = containers.flow_id\").\n\t\t\t\tWhere(\"f.user_id = ?\", uid)\n\t\t}\n\t} else {\n\t\tlogger.FromContext(c).Errorf(\"error filtering user role permissions: permission not found\")\n\t\tresponse.Error(c, response.ErrNotPermitted, nil)\n\t\treturn\n\t}\n\n\tquery.Init(\"containers\", containersSQLMappers)\n\n\tif query.Group != \"\" {\n\t\tif _, ok := containersSQLMappers[query.Group]; !ok {\n\t\t\tlogger.FromContext(c).Errorf(\"error finding containers grouped: group field not found\")\n\t\t\tresponse.Error(c, response.ErrContainersInvalidRequest, errors.New(\"group field not found\"))\n\t\t\treturn\n\t\t}\n\n\t\tvar respGrouped containersGrouped\n\t\tif respGrouped.Total, err = query.QueryGrouped(s.db, &respGrouped.Grouped, scope); err != nil {\n\t\t\tlogger.FromContext(c).WithError(err).Errorf(\"error finding containers grouped\")\n\t\t\tresponse.Error(c, response.ErrInternal, err)\n\t\t\treturn\n\t\t}\n\n\t\tresponse.Success(c, http.StatusOK, respGrouped)\n\t\treturn\n\t}\n\n\tif resp.Total, err = query.Query(s.db, &resp.Containers, scope); err != nil {\n\t\tlogger.FromContext(c).WithError(err).Errorf(\"error finding containers\")\n\t\tresponse.Error(c, response.ErrInternal, err)\n\t\treturn","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/server/services/containers.go#L83-L119","documentation":"GetContainers checks the `group` query parameter against containersSQLMappers before running the grouped container count query. A value not in the whitelist is rejected with Containers.InvalidRequest and message 'group field not found', preventing unvalidated input in the GROUP BY SQL.","triggerScenarios":"GET /containers?group=<field> where <field> is absent from containersSQLMappers — e.g. group=container_image when the mapper exposes group=image.","commonSituations":"Dashboard code grouping by a field renamed in a backend update; using fields valid on the flow-scoped variant that were removed from the shared mapper; scripts written against an older API version.","solutions":["Use an exact key from containersSQLMappers (backend/pkg/server/services/containers.go)","Verify allowed values in the Swagger docs for GET /containers","Remove the group parameter for ungrouped listing","Add the desired field to containersSQLMappers via a code change"],"exampleFix":"// before\nGET /api/v1/containers?group=container_status\n// after\nGET /api/v1/containers?group=status  (valid mapper key)","handlingStrategy":"validation","validationCode":"const containersGroups = [\"type\",\"status\",\"flow\",\"node\"];\nfunction assertValidGroup(g?: string) {\n  if (g && !containersGroups.includes(g)) {\n    throw new Error(`invalid containers group: ${g}`);\n  }\n}\nassertValidGroup(group);","typeGuard":"function isContainersGroup(g: string): g is typeof containersGroups[number] {\n  return (containersGroups as string[]).includes(g);\n}","tryCatchPattern":"try {\n  return await api.get('/containers', { params: { group } });\n} catch (e) {\n  if (e.response?.data?.code === 'Containers.InvalidRequest') {\n    // retry without grouping\n    return await api.get('/containers');\n  }\n  throw e;\n}","preventionTips":["Validate the group field against the mapper whitelist before calling the API","Use TypeScript union types for group params","Add CI tests covering each valid group value"],"tags":["api","validation","query-params","grouping"],"backgroundTag":"invalid-group-field","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}