{"record":{"id":"40a21627b3adac5e","repo":"vxcontrol/pentagi","slug":"failed-to-get-subtask-primary-msg-chains-for-subta","errorCode":null,"errorMessage":"failed to get subtask primary msg chains for subtask %d: %w","messagePattern":"failed to get subtask primary msg chains for subtask (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/controller/subtask.go","lineNumber":114,"sourceCode":"\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,\n\t\t\tTaskContext:        *taskCtx,\n\t\t},\n\t\tupdater:   updater,\n\t\tcompleted: completed,\n\t\twaiting:   waiting,","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/subtask.go#L96-L132","documentation":"After resolving the subtask status, LoadSubtaskWorker fetches the subtask's primary message chains via GetSubtaskPrimaryMsgChains. This error wraps any database failure of that query, tagged with the subtask ID. The worker cannot be constructed without its message chain.","triggerScenarios":"LoadSubtaskWorker proceeds past the status switch and GetSubtaskPrimaryMsgChains fails — DB unreachable, query timeout, pgvector extension issues, or schema mismatch.","commonSituations":"Postgres restart in progress during recovery; missing pgvector extension after restoring a dump; migrations not applied so msg_chain tables/columns differ; connection-pool exhaustion under many concurrent loads.","solutions":["Check the wrapped DB error for connectivity vs schema causes.","Verify pgvector extension and msg-chain table migrations are installed (goose up).","Retry the load with backoff if the DB was transiently unavailable during startup recovery.","Inspect connection-pool settings if failures correlate with high concurrency."],"exampleFix":"// before\nchains, err := db.GetSubtaskPrimaryMsgChains(ctx, id)\nif err != nil {\n    panic(err)\n}\n// after\nchains, err := db.GetSubtaskPrimaryMsgChains(ctx, id)\nif err != nil {\n    return nil, fmt.Errorf(\"load msg chains for subtask %d (check pgvector/migrations): %w\", id, err)\n}","handlingStrategy":"retry","validationCode":"// ensure pgvector and required tables exist before loading chains\nvar ext bool\nerr := db.QueryRowContext(ctx,\n    `SELECT EXISTS(SELECT 1 FROM pg_extension WHERE extname='vector')`).Scan(&ext)\nif err != nil || !ext {\n    return fmt.Errorf(\"pgvector extension missing\")\n}","typeGuard":"func IsMsgChainQueryError(err error) bool {\n    return strings.Contains(err.Error(), \"primary msg chains\")\n}","tryCatchPattern":"worker, err := LoadSubtaskWorker(ctx, taskCtx, subtask)\nif err != nil {\n    if isTransientDBError(err) {\n        return retryWithBackoff(ctx, func() error {\n            worker, err = LoadSubtaskWorker(ctx, taskCtx, subtask)\n            return err\n        })\n    }\n    return fmt.Errorf(\"recovery failed for subtask %d: %w\", subtask.ID, err)\n}","preventionTips":["Verify pgvector extension and msg-chain migrations on every deploy.","Gate recovery/startup on a DB readiness probe.","Size the connection pool for the number of concurrent subtask loads.","Retry transient DB errors with capped exponential backoff."],"tags":["database","msg-chain","subtask"],"backgroundTag":"database-query-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}