{"record":{"id":"3e3bb6c9a9f68c9f","repo":"vxcontrol/pentagi","slug":"invalid-toolcallstatus-s","errorCode":null,"errorMessage":"invalid ToolcallStatus: %s","messagePattern":"invalid ToolcallStatus: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/server/models/toolcalls.go","lineNumber":32,"sourceCode":"\tToolcallStatusRunning  ToolcallStatus = \"running\"\n\tToolcallStatusFinished ToolcallStatus = \"finished\"\n\tToolcallStatusFailed   ToolcallStatus = \"failed\"\n)\n\nfunc (s ToolcallStatus) String() string {\n\treturn string(s)\n}\n\n// Valid is function to control input/output data\nfunc (s ToolcallStatus) Valid() error {\n\tswitch s {\n\tcase ToolcallStatusReceived,\n\t\tToolcallStatusRunning,\n\t\tToolcallStatusFinished,\n\t\tToolcallStatusFailed:\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid ToolcallStatus: %s\", s)\n\t}\n}\n\n// Validate is function to use callback to control input/output data\nfunc (s ToolcallStatus) Validate(db *gorm.DB) {\n\tif err := s.Valid(); err != nil {\n\t\tdb.AddError(err)\n\t}\n}\n\n// Toolcall is model to contain tool call information\n// nolint:lll\ntype Toolcall struct {\n\tID              uint64         `form:\"id\" json:\"id\" validate:\"min=0,numeric\" gorm:\"type:BIGINT;NOT NULL;PRIMARY_KEY;AUTO_INCREMENT\"`\n\tCallID          string         `form:\"call_id\" json:\"call_id\" validate:\"required\" gorm:\"type:TEXT;NOT NULL\"`\n\tStatus          ToolcallStatus `form:\"status\" json:\"status\" validate:\"valid,required\" gorm:\"type:TOOLCALL_STATUS;NOT NULL;default:'received'\"`\n\tName            string         `form:\"name\" json:\"name\" validate:\"required\" gorm:\"type:TEXT;NOT NULL\"`\n\tArgs            string         `form:\"args\" json:\"args\" validate:\"required\" gorm:\"type:JSON;NOT NULL\"`","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/server/models/toolcalls.go#L14-L50","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ncall.Status = models.ToolcallStatus(\"success\")\n// after\ncall.Status = models.ToolcallStatusFinished // \"finished\"","handlingStrategy":"validation","validationCode":"func isValidToolcallStatus(v string) bool {\n\tswitch models.ToolcallStatus(v) {\n\tcase models.ToolcallStatusReceived, models.ToolcallStatusRunning,\n\t\tmodels.ToolcallStatusFinished, models.ToolcallStatusFailed:\n\t\treturn true\n\t}\n\treturn false\n}","typeGuard":"func asToolcallStatus(v string) (models.ToolcallStatus, bool) {\n\ts := models.ToolcallStatus(v)\n\treturn s, s.Valid() == nil\n}","tryCatchPattern":"if err := status.Valid(); err != nil {\n\treturn fmt.Errorf(\"illegal toolcall status %q: %w\", status, err)\n}","preventionTips":["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."],"tags":["go","enum-validation","tools","gorm"],"backgroundTag":"invalid-enum-value","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}