{"record":{"id":"fb50b22c0e346ccf","repo":"vxcontrol/pentagi","slug":"unexpected-subtask-status-s","errorCode":null,"errorMessage":"unexpected subtask status: %s","messagePattern":"unexpected subtask status: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/controller/subtask.go","lineNumber":109,"sourceCode":"\tcase database.SubtaskStatusFinished, database.SubtaskStatusFailed:\n\t\tcompleted = true\n\tcase database.SubtaskStatusWaiting:\n\t\twaiting = true\n\tcase database.SubtaskStatusRunning:\n\t\tvar err error\n\t\t// if subtask is running, it means that it was not finished by previous run\n\t\t// so we need to set it to created and continue from the beginning\n\t\tsubtask, err = taskCtx.DB.UpdateSubtaskStatus(ctx, database.UpdateSubtaskStatusParams{\n\t\t\tStatus: database.SubtaskStatusCreated,\n\t\t\tID:     subtask.ID,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to update subtask %d status to created: %w\", subtask.ID, err)\n\t\t}\n\tcase database.SubtaskStatusCreated:\n\t\treturn nil, fmt.Errorf(\"subtask %d has created yet: %w\", subtask.ID, ErrNothingToLoad)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unexpected subtask status: %s\", subtask.Status)\n\t}\n\n\tmsgChains, err := taskCtx.DB.GetSubtaskPrimaryMsgChains(ctx, database.Int64ToNullInt64(&subtask.ID))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get subtask primary msg chains for subtask %d: %w\", subtask.ID, err)\n\t}\n\n\tif len(msgChains) == 0 {\n\t\treturn nil, fmt.Errorf(\"subtask %d has no msg chains: %w\", subtask.ID, ErrNothingToLoad)\n\t}\n\n\treturn &subtaskWorker{\n\t\tmx: &sync.RWMutex{},\n\t\tsubtaskCtx: &SubtaskContext{\n\t\t\tMsgChainID:         msgChains[0].ID,\n\t\t\tSubtaskID:          subtask.ID,\n\t\t\tSubtaskTitle:       subtask.Title,\n\t\t\tSubtaskDescription: subtask.Description,","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/subtask.go#L91-L127","documentation":"LoadSubtaskWorker hits its default switch branch when the subtask's status is none of the handled values (processed/created handling above), i.e. an unrecognized or intentionally un-settable status (such as 'created' set via this path or a corrupted value). It returns the raw status string for diagnosis.","triggerScenarios":"A subtask row has a status value outside the enumerated cases in LoadSubtaskWorker — e.g. status 'failed'/'finished' passed to a loader, or a status string from an older schema version not matching current constants.","commonSituations":"Loading subtasks after a version upgrade where the status enum changed; DB rows manually edited; a bug elsewhere set an unexpected status; passing finished subtasks through the resume path.","solutions":["Log the subtask ID and status value; confirm what the actual stored status is.","Filter out terminal-status subtasks (finished/failed) before calling LoadSubtaskWorker.","After a version upgrade, run all goose migrations and verify status enum values match database.SubtaskStatus* constants.","Add an explicit case for any newly introduced status in the switch."],"exampleFix":"// before\nsubtasks := taskCtx.DB.GetAllSubtasks(ctx)\nfor _, s := range subtasks {\n    LoadSubtaskWorker(ctx, taskCtx, s)\n}\n// after\nsubtasks := taskCtx.DB.GetAllSubtasks(ctx)\nfor _, s := range subtasks {\n    if s.Status == database.SubtaskStatusFinished || s.Status == database.SubtaskStatusFailed {\n        continue // skip terminal subtasks\n    }\n    LoadSubtaskWorker(ctx, taskCtx, s)\n}","handlingStrategy":"validation","validationCode":"switch subtask.Status {\ncase database.SubtaskStatusProcessed, database.SubtaskStatusProcessing:\n    // ok to load\ndefault:\n    return fmt.Errorf(\"skip subtask %d: unsupported status %q\", subtask.ID, subtask.Status)\n}","typeGuard":"func IsLoadableStatus(s database.SubtaskStatus) bool {\n    switch s {\n    case database.SubtaskStatusProcessed, database.SubtaskStatusProcessing:\n        return true\n    }\n    return false\n}","tryCatchPattern":"if !IsLoadableStatus(subtask.Status) {\n    log.Warn(\"unexpected subtask status\", \"id\", subtask.ID, \"status\", subtask.Status)\n    return nil // skip rather than propagate\n}\nworker, err := LoadSubtaskWorker(ctx, taskCtx, subtask)\nif err != nil { return err }","preventionTips":["Filter terminal statuses (finished/failed) out before any resume/load pass.","After enum changes, re-run migrations and verify stored values match constants.","Never hand-edit status columns in the DB.","When adding a status constant, update every switch over SubtaskStatus."],"tags":["state-machine","unexpected-value","subtask"],"backgroundTag":"unexpected-enum-value","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}