plandex-ai/plandex · error
error scanning deleted draft plan id: %v
Error message
error scanning deleted draft plan id: %v
What it means
While iterating rows returned by the draft-plan DELETE, res.Scan(&id) failed to copy a RETURNING id value into a string. With DELETE ... RETURNING id this normally only fails on driver/protocol errors, NULL ids, or rows.Next/Scan misuse.
Source
Thrown at app/server/db/plan_helpers.go:367
return nil
}
func DeleteDraftPlans(orgId, projectId, userId string) error {
res, err := Conn.Query("DELETE FROM plans WHERE project_id = $1 AND owner_id = $2 AND name = 'draft' RETURNING id;", projectId, userId)
if err != nil {
return fmt.Errorf("error deleting draft plans: %v", err)
}
defer res.Close()
// get ids
var ids []string
for res.Next() {
var id string
err := res.Scan(&id)
if err != nil {
return fmt.Errorf("error scanning deleted draft plan id: %v", err)
}
ids = append(ids, id)
}
errCh := make(chan error, len(ids))
for _, planId := range ids {
go func(planId string) {
defer func() {
if r := recover(); r != nil {
log.Printf("panic in DeleteDraftPlans: %v\n%s", r, debug.Stack())
errCh <- fmt.Errorf("panic in DeleteDraftPlans: %v\n%s", r, debug.Stack())
runtime.Goexit() // don't allow outer function to continue and double-send to channel
}
}()
errCh <- DeletePlanDir(orgId, planId)
}(planId)
}
View on GitHub (pinned to e2d772072e)
Solutions
- Confirm RETURNING list matches the Scan arguments exactly
- Check the wrapped driver error for connection/protocol issues
- Ensure the id column is NOT NULL primary key
- Use errors.Is/As with pq errors for precise diagnosis
Example fix
// before
var id string
err := res.Scan(&id)
if err != nil {
return fmt.Errorf("error scanning deleted draft plan id: %v", err)
}
// after
var id string
if err := res.Scan(&id); err != nil {
return fmt.Errorf("error scanning deleted draft plan id: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// verify RETURNING columns match Scan args // query: DELETE FROM plans WHERE ... RETURNING id; -> Scan(&id) only
Try / catch
if err := DeleteDraftPlans(orgId, projectId, userId); err != nil {
if errors.Is(err, driver.ErrBadConn) || errors.Is(err, io.EOF) {
// connection lost mid-result-set; retry the operation
}
return err
} Prevention
- Keep RETURNING column list and Scan args in lockstep
- Enforce NOT NULL primary keys in schema
- Handle rows.Err() after iteration loops
- Use %w wrapping for errors.As diagnostics
When it happens
Trigger: res.Scan(&id) errors during the rows loop: driver connection lost mid-result-set, id column NULL, or the query was changed to return extra columns that no longer match Scan args.
Common situations: Connection reset while streaming large result sets; someone added columns to RETURNING without updating Scan; NULL id values from schema changes allowing NULL primary keys.
Related errors
- error adding plan context tokens: %v
- unsupported data type: %T
- error scanning repo lock: %v
- error inserting new lock: %v
- error committing transaction: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/cb0fb22742e00569.
Report an issue: GitHub.