{"record":{"id":"442620f809bc496b","repo":"vxcontrol/pentagi","slug":"assistantlogs-invalidrequest","errorCode":"Assistantlogs.InvalidRequest","errorMessage":"group field not found","messagePattern":"group field not found","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"backend/pkg/server/services/assistantlogs.go","lineNumber":99,"sourceCode":"\t\t}\n\t} else if slices.Contains(privs, \"assistantlogs.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 = 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(\"assistantlogs\", assistantlogsSQLMappers)\n\n\tif query.Group != \"\" {\n\t\tif _, ok := assistantlogsSQLMappers[query.Group]; !ok {\n\t\t\tlogger.FromContext(c).Errorf(\"error finding assistantlogs grouped: group field not found\")\n\t\t\tresponse.Error(c, response.ErrAssistantlogsInvalidRequest, errors.New(\"group field not found\"))\n\t\t\treturn\n\t\t}\n\n\t\tvar respGrouped assistantlogsGrouped\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 assistantlogs 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.AssistantLogs, scope); err != nil {\n\t\tlogger.FromContext(c).WithError(err).Errorf(\"error finding assistantlogs\")\n\t\tresponse.Error(c, response.ErrInternal, err)\n\t\treturn","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/server/services/assistantlogs.go#L81-L117","documentation":"GetAssistantlogs validates the `group` query parameter against the assistantlogsSQLMappers whitelist before running a grouped aggregation query. If the requested group field is not a recognized column alias, the request is rejected as Assistantlogs.InvalidRequest with the message 'group field not found'. This prevents arbitrary or misspelled fields from being interpolated into the GROUP BY SQL clause.","triggerScenarios":"A GET /assistantlogs request that includes a `group=<field>` query parameter whose value is not a key in assistantlogsSQLMappers (e.g. group=Type vs group=type, or a field that does not exist).","commonSituations":"Clients passing snake_case DB column names instead of the documented camelCase aliases; API version drift after a rename of a groupable field; copy-pasted grouping code between endpoints with different mapper sets; hand-built dashboard queries.","solutions":["Inspect the assistantlogsSQLMappers map in backend/pkg/server/services/assistantlogs.go and use one of its exact keys as the group value","Check the REST/Swagger docs for the list of allowed group fields for the assistantlogs endpoint","Remove the group parameter entirely to fetch ungrouped results","If the field genuinely should be groupable, add it to assistantlogsSQLMappers (and the underlying SQL mapper) in a code change"],"exampleFix":"// before\nGET /api/v1/assistantlogs?group=flow_type\n// after\nGET /api/v1/assistantlogs?group=type  (a key present in assistantlogsSQLMappers)","handlingStrategy":"validation","validationCode":"const allowedGroups = [\"type\",\"flow\",\"status\"]; // keys of assistantlogsSQLMappers\nfunction isValidGroup(g?: string): boolean {\n  return !g || allowedGroups.includes(g);\n}\nif (!isValidGroup(group)) throw new Error(`invalid group field: ${group}`);","typeGuard":"function isAssistantlogsGroup(g: string): g is typeof allowedGroups[number] {\n  return (allowedGroups as string[]).includes(g);\n}","tryCatchPattern":"try {\n  const res = await api.get('/assistantlogs', { params: { group } });\n} catch (e) {\n  if (e.response?.data?.code === 'Assistantlogs.InvalidRequest') {\n    // fall back to ungrouped listing\n    return api.get('/assistantlogs');\n  }\n  throw e;\n}","preventionTips":["Derive the group param from a constant list shared with the API docs, never free text","Validate query params with zod before issuing the request","Add an integration test per groupable field"],"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"}