vxcontrol/pentagi · warning
ErrScreenshotsInvalidRequest
ErrScreenshotsInvalidRequest
Error message
group field not found
What it means
GetScreenshots supports a grouped query mode via the `group` query parameter. The parameter must name a field present in screenshotsSQLMappers (the allow-list of groupable columns). If query.Group is non-empty but not a key of that map, the request is rejected with ErrScreenshotsInvalidRequest before any SQL runs.
Source
Thrown at backend/pkg/server/services/screenshots.go:102
}
} else if slices.Contains(privs, "screenshots.view") {
scope = func(db *gorm.DB) *gorm.DB {
return db.
Joins("INNER JOIN flows f ON f.id = screenshots.flow_id").
Where("f.user_id = ?", uid)
}
} else {
logger.FromContext(c).Errorf("error filtering user role permissions: permission not found")
response.Error(c, response.ErrNotPermitted, nil)
return
}
query.Init("screenshots", screenshotsSQLMappers)
if query.Group != "" {
if _, ok := screenshotsSQLMappers[query.Group]; !ok {
logger.FromContext(c).Errorf("error finding screenshots grouped: group field not found")
response.Error(c, response.ErrScreenshotsInvalidRequest, errors.New("group field not found"))
return
}
var respGrouped screenshotsGrouped
if respGrouped.Total, err = query.QueryGrouped(s.db, &respGrouped.Grouped, scope); err != nil {
logger.FromContext(c).WithError(err).Errorf("error finding screenshots grouped")
response.Error(c, response.ErrInternal, err)
return
}
response.Success(c, http.StatusOK, respGrouped)
return
}
if resp.Total, err = query.Query(s.db, &resp.Screenshots, scope); err != nil {
logger.FromContext(c).WithError(err).Errorf("error finding screenshots")
response.Error(c, response.ErrInternal, err)
returnView on GitHub (pinned to ea665308ba)
Solutions
- Inspect screenshotsSQLMappers in backend/pkg/server/services/screenshots.go and use exactly one of its keys as the group value.
- Correct or remove the group query parameter from the request.
- If a new field genuinely needs grouping support, add it to screenshotsSQLMappers in the backend and redeploy.
- Check the frontend/API client for stale or hardcoded group values after schema changes.
Example fix
// before GET /api/v1/screenshots?group=created // after (created is not in screenshotsSQLMappers) GET /api/v1/screenshots?group=created_at
Defensive patterns
Strategy: validation
Validate before calling
const SCREENSHOTS_GROUP_FIELDS = ['type', 'created_at']; // keys of screenshotsSQLMappers
if (group && !SCREENSHOTS_GROUP_FIELDS.includes(group)) {
throw new Error(`invalid group field for screenshots: ${group}`);
} Type guard
function isValidScreenshotGroup(g) {
return typeof g === 'string' && SCREENSHOTS_GROUP_FIELDS.includes(g);
} Try / catch
try {
return await api.getScreenshots({ group });
} catch (e) {
if (e.code === 'ErrScreenshotsInvalidRequest' && e.message === 'group field not found') {
return await api.getScreenshots({}); // fall back to ungrouped listing
}
throw e;
} Prevention
- Keep the client's group-by options in sync with the backend SQL mapper maps.
- Validate the group parameter against an allow-list before sending the request.
- Never reuse group field names across different entity endpoints; each has its own mapper.
- On this 400, retry once without the group parameter instead of failing the UI.
When it happens
Trigger: GET /screenshots?group=<field> where <field> is not one of the mapped/groupable columns for screenshots (e.g. a misspelled field, a column that exists in the table but is not in screenshotsSQLMappers, or an arbitrary string).
Common situations: Frontend sending a group field renamed after a backend refactor of the SQL mappers; API consumers guessing field names; case mismatch (e.g. group=FlowID vs flow_id style names); passing group together with filters copied from another entity's endpoint.
Related errors
- ErrSearchlogsInvalidRequest
- ErrSubtasksInvalidRequest
- ErrTasksInvalidRequest
- ErrTermlogsInvalidRequest
- Internal
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/6737d26edd6a14fa.
Report an issue: GitHub.