vxcontrol/pentagi · error
invalid ToolcallStatus: %s
Error message
invalid ToolcallStatus: %s
What it means
ToolcallStatus tracks a tool call's lifecycle: received, running, finished, failed. ToolcallStatus.Valid() rejects any other string with this error, and the GORM Validate callback enforces the whitelist whenever a Toolcall row is inserted or updated.
Source
Thrown at backend/pkg/server/models/toolcalls.go:32
ToolcallStatusRunning ToolcallStatus = "running"
ToolcallStatusFinished ToolcallStatus = "finished"
ToolcallStatusFailed ToolcallStatus = "failed"
)
func (s ToolcallStatus) String() string {
return string(s)
}
// Valid is function to control input/output data
func (s ToolcallStatus) Valid() error {
switch s {
case ToolcallStatusReceived,
ToolcallStatusRunning,
ToolcallStatusFinished,
ToolcallStatusFailed:
return nil
default:
return fmt.Errorf("invalid ToolcallStatus: %s", s)
}
}
// Validate is function to use callback to control input/output data
func (s ToolcallStatus) Validate(db *gorm.DB) {
if err := s.Valid(); err != nil {
db.AddError(err)
}
}
// Toolcall is model to contain tool call information
// nolint:lll
type Toolcall struct {
ID uint64 `form:"id" json:"id" validate:"min=0,numeric" gorm:"type:BIGINT;NOT NULL;PRIMARY_KEY;AUTO_INCREMENT"`
CallID string `form:"call_id" json:"call_id" validate:"required" gorm:"type:TEXT;NOT NULL"`
Status ToolcallStatus `form:"status" json:"status" validate:"valid,required" gorm:"type:TOOLCALL_STATUS;NOT NULL;default:'received'"`
Name string `form:"name" json:"name" validate:"required" gorm:"type:TEXT;NOT NULL"`
Args string `form:"args" json:"args" validate:"required" gorm:"type:JSON;NOT NULL"`View on GitHub (pinned to ea665308ba)
Solutions
- Restrict all transitions to received, running, finished, failed using the models.ToolcallStatus* constants from backend/pkg/server/models/toolcalls.go.
- Map outcome-specific states (timeout, cancelled) onto ToolcallStatusFailed with a reason stored in the result field, not as new status strings.
- Default new Toolcall structs to models.ToolcallStatusReceived (matches the DB default 'received') so the zero value never reaches Valid().
- Validate at the executor boundary — call Valid() before each Create/Update so a bad status fails fast with context.
Example fix
// before
call.Status = models.ToolcallStatus("success")
// after
call.Status = models.ToolcallStatusFinished // "finished" Defensive patterns
Strategy: validation
Validate before calling
func isValidToolcallStatus(v string) bool {
switch models.ToolcallStatus(v) {
case models.ToolcallStatusReceived, models.ToolcallStatusRunning,
models.ToolcallStatusFinished, models.ToolcallStatusFailed:
return true
}
return false
} Type guard
func asToolcallStatus(v string) (models.ToolcallStatus, bool) {
s := models.ToolcallStatus(v)
return s, s.Valid() == nil
} Try / catch
if err := status.Valid(); err != nil {
return fmt.Errorf("illegal toolcall status %q: %w", status, err)
} Prevention
- Initialize every Toolcall with ToolcallStatusReceived and transition only through the four constants.
- Record timeouts/cancellations as ToolcallStatusFailed plus a reason field, never as new status strings.
- Validate status before each Create/Update in the tool-call repository layer.
- Keep a test that walks received→running→finished/failed through Valid() to catch enum drift.
When it happens
Trigger: Updating a tool call record with a status outside the four-value set (e.g. 'pending', 'success', 'error', 'timeout'); agent orchestration code building statuses dynamically; deserializing tool call state from JSON produced by another system with a different status vocabulary.
Common situations: Synonym drift ('success' vs 'finished', 'error' vs 'failed') when wiring new tool executors; timeouts implemented as a distinct status string instead of setting failed; leftover zero-value ('') Toolcall.Status on structs created without defaulting.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- invalid MsgchainType: %s
- invalid MsglogType: %s
- invalid MsglogResultFormat: %s
- invalid PromptType: %s
- invalid SearchEngineType: %s
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/3e3bb6c9a9f68c9f.
Report an issue: GitHub.