vxcontrol/pentagi · error

ErrToolcallsInvalidRequest

ErrToolcallsInvalidRequest

Error message

group field not found

What it means

GetToolcalls rejects grouping requests whose `group` query parameter names a field that has no entry in the toolcalls SQL mapper table. Before running a grouped aggregation, the handler looks up query.Group in toolcallsSQLMappers; a miss means the requested grouping column is not whitelisted, so the request is refused as an invalid request (HTTP 400 class) instead of building SQL from untrusted input.

Source

Thrown at backend/pkg/server/services/toolcalls.go:103

		}
	} else if slices.Contains(privs, "toolcalls.view") {
		scope = func(db *gorm.DB) *gorm.DB {
			return db.
				Joins("INNER JOIN flows f ON f.id = toolcalls.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("toolcalls", toolcallsSQLMappers)

	if query.Group != "" {
		if _, ok := toolcallsSQLMappers[query.Group]; !ok {
			logger.FromContext(c).Errorf("error finding toolcalls grouped: group field not found")
			response.Error(c, response.ErrToolcallsInvalidRequest, errors.New("group field not found"))
			return
		}

		var respGrouped toolcallsGrouped
		if respGrouped.Total, err = query.QueryGrouped(s.db, &respGrouped.Grouped, scope); err != nil {
			logger.FromContext(c).WithError(err).Errorf("error finding toolcalls grouped")
			response.Error(c, response.ErrInternal, err)
			return
		}

		response.Success(c, http.StatusOK, respGrouped)
		return
	}

	if resp.Total, err = query.Query(s.db, &resp.Toolcalls, scope); err != nil {
		logger.FromContext(c).WithError(err).Errorf("error finding toolcalls")
		response.Error(c, response.ErrInternal, err)
		return

View on GitHub (pinned to ea665308ba)

Solutions

  1. Check the allowed group keys in toolcallsSQLMappers in backend/pkg/server/services/toolcalls.go and use one of them verbatim as the group query param
  2. Fix typos or casing in the group query parameter sent by the client
  3. If the field should be groupable, add it to toolcallsSQLMappers so query.Init registers it
  4. Verify the frontend is not sending a leftover/renamed group param from an older API version

Example fix

// before
GET /api/v1/toolcalls?group=toolNane
// after
GET /api/v1/toolcalls?group=toolName
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED_GROUPS = ['status','type','created_at']; // mirror toolcallsSQLMappers
if (group && !ALLOWED_GROUPS.includes(group)) {
  throw new Error(`invalid group field: ${group}`);
}
await api.get(`/toolcalls?group=${encodeURIComponent(group)}`);

Type guard

function isValidGroupField(v: unknown): v is string {
  return typeof v === 'string' && ['status','type','created_at'].includes(v);
}

Try / catch

try {
  const res = await api.getToolcalls({ group });
} catch (e) {
  if (e.response?.data?.code === 'ErrToolcallsInvalidRequest') {
    console.warn('Unsupported group field, retrying ungrouped');
    return api.getToolcalls({});
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling GET /toolcalls?group=<field> where <field> is not one of the keys registered in toolcallsSQLMappers (e.g. a typo like 'statues' instead of 'status', a field that exists on the model but was never added to the mapper, or a non-groupable field).

Common situations: Developers hand-writing group params against the REST API with stale docs, frontends sending renamed fields after a schema change, or a new column added to the model without registering it in toolcallsSQLMappers.

Understand the failure class

Background: "Invalid query parameter" / "Failed to parse value of ...": fixing bad query string parameters across APIs — this error's family across 36 libraries.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/622e3a7a2ded929f. Report an issue: GitHub.