{"record":{"id":"d174d54cea58864f","repo":"vxcontrol/pentagi","slug":"internal","errorCode":"Internal","errorMessage":"wrong field for grouping","messagePattern":"wrong field for grouping","errorType":"validation","errorClass":null,"httpStatus":500,"severity":"error","filePath":"backend/pkg/server/rdb/table.go","lineNumber":94,"sourceCode":"\t\tswitch t := v.(type) {\n\t\tcase string:\n\t\t\tt = q.DoConditionFormat(t)\n\t\t\tif isNumbericField(k) {\n\t\t\t\tq.sqlMappers[k] = t\n\t\t\t} else {\n\t\t\t\tq.sqlMappers[k] = \"LOWER(\" + t + \"::text)\"\n\t\t\t}\n\t\tcase func(q *TableQuery, db *gorm.DB, value any) *gorm.DB:\n\t\t\tq.sqlMappers[k] = t\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\t}\n\tif q.Group != \"\" {\n\t\tvar ok bool\n\t\tq.groupField, ok = q.sqlMappers[q.Group].(string)\n\t\tif !ok {\n\t\t\treturn errors.New(\"wrong field for grouping\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// DoConditionFormat is auxiliary function to prepare condition to the table\nfunc (q *TableQuery) DoConditionFormat(cond string) string {\n\tcond = strings.ReplaceAll(cond, \"{{type}}\", q.Type)\n\tcond = strings.ReplaceAll(cond, \"{{table}}\", q.table)\n\tcond = strings.ReplaceAll(cond, \"{{page}}\", strconv.Itoa(q.Page))\n\tcond = strings.ReplaceAll(cond, \"{{size}}\", strconv.Itoa(q.Size))\n\treturn cond\n}\n\n// SetFilters is function to set custom filters to build target SQL query\nfunc (q *TableQuery) SetFilters(sqlFilters []func(*gorm.DB) *gorm.DB) {\n\tq.sqlFilters = sqlFilters\n}","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/server/rdb/table.go#L76-L112","documentation":"TableQuery.Init validates the query's Group parameter by looking it up in the table's sqlMappers and asserting the mapped value is a plain string (a SQL column expression). Grouping can only be done on a real column/expression, not on a mapper that holds a function (e.g. a custom search projection like the 'data' concatenation mapper). If the group name is unknown or maps to a non-string value, Init returns this sentinel error and the query is rejected before touching the database.","triggerScenarios":"Calling a list endpoint (e.g. ListDocuments / GET with rdb.TableQuery query params) with ?group=<name> where <name> is either not a key in the table's sqlMappers map, or maps to a func/complex value instead of a SQL string expression.","commonSituations":"Frontend sends a group field that was renamed or removed from the backend mapper map; user passes an arbitrary JSON/query field name; developer added a mapper entry as a function and someone tries to group by it; typos like 'flowID' vs 'flow_id'.","solutions":["Use only field names present in the table's sqlMappers as the group value (e.g. for agentlogs: id, initiator, executor, task, result, flow_id, task_id, subtask_id, created_at).","If a new groupable field is needed, add it to the sqlMappers map as a plain string SQL expression (e.g. \"{{table}}.my_column\"), not a func.","Remove or fix the group query parameter in the client request; fall back to no grouping.","Check that the mapper value's type is string — grouping on function-based mappers is unsupported by design."],"exampleFix":"// before\nGET /agentlogs?group=data        // 'data' mapper is a concat expression or func -> fails\n// after\nGET /agentlogs?group=task        // string column mapper -> Init succeeds","handlingStrategy":"validation","validationCode":"const allowedGroups = [\"id\",\"initiator\",\"executor\",\"task\",\"result\",\"flow_id\",\"task_id\",\"subtask_id\",\"created_at\"];\nfunction isGroupValid(g) { return !g || allowedGroups.includes(g); }\nif (!isGroupValid(params.group)) throw new Error(`group must be one of: ${allowedGroups.join(\", \")}`);","typeGuard":"function isStringMapper(v) { return typeof v === \"string\"; }","tryCatchPattern":"try {\n  if err := query.Init(table, mappers); err != nil {\n    if err.Error() == \"wrong field for grouping\" { return http.StatusBadRequest }\n    return http.StatusInternalServerError\n  }\n} catch (/wrong field for grouping/) { /* fix group param */ }","preventionTips":["Derive the group dropdown in the UI from the same mapper list the backend uses.","Always call Init before using a TableQuery.","Add a unit test asserting every groupable mapper value is a string.","Never forward raw user query params into Group without whitelisting."],"tags":["sql","grouping","query-params","validation"],"backgroundTag":"invalid-group-field","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}