{"record":{"id":"689bdbd7dec07ed7","repo":"plandex-ai/plandex","slug":"failed-to-store-plan-subtasks-v","errorCode":null,"errorMessage":"failed to store plan subtasks: %v","messagePattern":"failed to store plan subtasks: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/model/plan/tell_stream_store.go","lineNumber":190,"sourceCode":"\t\terr = db.StoreDescription(description)\n\n\t\tif err != nil {\n\t\t\tstate.onError(onErrorParams{\n\t\t\t\tstreamErr:      fmt.Errorf(\"failed to store description: %v\", err),\n\t\t\t\tstoreDesc:      false,\n\t\t\t\tconvoMessageId: assistantMsg.Id,\n\t\t\t\tcommitMsg:      convoCommitMsg,\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\t\tlog.Println(\"[storeOnFinished] Description stored\")\n\n\t\t// store subtasks\n\t\terr = db.StorePlanSubtasks(currentOrgId, planId, state.subtasks)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Error storing plan subtasks: %v\\n\", err)\n\t\t\tstate.onError(onErrorParams{\n\t\t\t\tstreamErr:      fmt.Errorf(\"failed to store plan subtasks: %v\", err),\n\t\t\t\tstoreDesc:      false,\n\t\t\t\tconvoMessageId: assistantMsg.Id,\n\t\t\t\tcommitMsg:      convoCommitMsg,\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\n\t\tlog.Println(\"Comitting after store on finished\")\n\n\t\terr = repo.GitAddAndCommit(branch, convoCommitMsg)\n\t\tif err != nil {\n\t\t\tstate.onError(onErrorParams{\n\t\t\t\tstreamErr:      fmt.Errorf(\"failed to commit: %v\", err),\n\t\t\t\tstoreDesc:      false,\n\t\t\t\tconvoMessageId: assistantMsg.Id,\n\t\t\t\tcommitMsg:      convoCommitMsg,\n\t\t\t})\n\t\t\treturn err","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/model/plan/tell_stream_store.go#L172-L208","documentation":"Thrown in storeOnFinished (tell_stream_store.go:190) when db.StorePlanSubtasks fails to persist the plan's subtask list to the database after an assistant streaming reply has already been stored and a description written. The library wraps the underlying db error so the caller knows persistence of subtasks (the plan/task breakdown) failed at the end of a streaming tell operation. The onError handler fires with the wrapped error and the store loop returns the error, surfacing a 500 'Error storing on finished' to the client.","triggerScenarios":"db.StorePlanSubtasks(currentOrgId, planId, state.subtasks) returns a non-nil error — typically a database connection failure, lock timeout, constraint violation, or serialization failure while writing the subtasks rows for the current org/plan at the conclusion of a tell stream.","commonSituations":"Database restart or connection pool exhaustion mid-stream; concurrent writes to the same plan row from another session causing lock contention/serialization errors; schema mismatch after upgrading the server without running migrations; disk-full on the database host.","solutions":["Inspect the wrapped '%v' cause in server logs ('Error storing plan subtasks: ...') to identify the underlying db error (connection, lock, constraint).","Verify database connectivity and run pending migrations; retry the tell operation once the DB is healthy.","Check for concurrent writers on the same plan and reduce contention, or enable retry/backoff on StorePlanSubtasks.","If a constraint is violated, validate state.subtasks before the call (non-nil ids, valid planId) and repair stale subtask data."],"exampleFix":"// before\ncurrentSubtasks := state.subtasks\nerr = db.StorePlanSubtasks(currentOrgId, planId, currentSubtasks)\n// after\nif err := retry(3, func() error {\n    return db.StorePlanSubtasks(currentOrgId, planId, state.subtasks)\n}); err != nil {\n    return fmt.Errorf(\"failed to store plan subtasks: %w\", err)\n}","handlingStrategy":"retry","validationCode":"if state.subtasks == nil || planId == \"\" || currentOrgId == \"\" {\n    return fmt.Errorf(\"invalid subtask store inputs: planId=%q orgId=%q subtasks=%d\", planId, currentOrgId, len(state.subtasks))\n}\nif err := db.Ping(); err != nil {\n    return fmt.Errorf(\"database unavailable before storing subtasks: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := db.StorePlanSubtasks(orgId, planId, subtasks); err != nil {\n    var retryable bool = isTransientDbError(err) // e.g. net errors, lock timeouts\n    if retryable {\n        time.Sleep(backoff); return retryOnce()\n    }\n    return fmt.Errorf(\"failed to store plan subtasks: %w\", err)\n}","preventionTips":["Check database health (ping/health endpoint) before long streaming operations.","Apply idempotent retry with backoff around StorePlanSubtasks.","Run migrations as part of deploy so schema always matches the binary.","Monitor DB connection-pool saturation and lock wait metrics."],"tags":["database","persistence","plan-subtasks","streaming"],"backgroundTag":"database-write-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}