{"record":{"id":"63512427ae593475","repo":"plandex-ai/plandex","slug":"error-storing-default-plan-config-v","errorCode":null,"errorMessage":"error storing default plan config: %v","messagePattern":"error storing default plan config: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/plan_config_helpers.go","lineNumber":61,"sourceCode":"\tvar config shared.PlanConfig\n\terr := Conn.Get(&config, query, userId)\n\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting default plan config: %v\", err)\n\t}\n\n\treturn &config, nil\n}\n\nfunc StoreDefaultPlanConfig(userId string, config *shared.PlanConfig, tx *sqlx.Tx) error {\n\tquery := `\n\t\tUPDATE users SET default_plan_config = $1 WHERE id = $2\n\t`\n\n\t_, err := tx.Exec(query, config, userId)\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error storing default plan config: %v\", err)\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":43,"sourceCodeEnd":66,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/plan_config_helpers.go#L43-L66","documentation":"StoreDefaultPlanConfig wraps a failure of `UPDATE users SET default_plan_config = $1 WHERE id = $2` executed on the caller-supplied transaction (tx.Exec) with this message. Because it runs on a tx, this error typically also aborts the surrounding transaction via WithTx.","triggerScenarios":"Called with a nil or already-committed/rolled-back *sqlx.Tx (nil pointer dereference or 'tx has been committed' error), the users row doesn't exist (silent zero-row update — not this error), DB connection lost, or the PlanConfig cannot be driver-encoded.","commonSituations":"Transaction context canceled mid-flight (WithTx with a canceled ctx); caller reuses a tx after an earlier error; connection-pool exhaustion; schema drift removing default_plan_config.","solutions":["Ensure a valid, non-nil, still-open *sqlx.Tx is passed and that no earlier statement in the transaction already failed","Inspect the wrapped cause: connection errors mean check Postgres health/DATABASE_URL and retry the whole transaction","Confirm migrations define users.default_plan_config","If the userId may not exist, check RowsAffected after Exec — a zero-row update succeeds silently and is a separate bug from this error"],"exampleFix":"// before\nerr = StoreDefaultPlanConfig(userId, config, tx) // tx may be dead after earlier error\n// after\nif err := doOtherWork(tx); err != nil {\n    return err // abort early so tx isn't reused in a broken state\n}\nif err := StoreDefaultPlanConfig(userId, config, tx); err != nil {\n    return err\n}","handlingStrategy":"try-catch","validationCode":"if tx == nil {\n    return errors.New(\"StoreDefaultPlanConfig requires an active transaction\")\n}\nvar exists bool\nConn.Get(&exists, \"SELECT EXISTS(SELECT 1 FROM users WHERE id=$1)\", userId)","typeGuard":null,"tryCatchPattern":"err := WithTx(ctx, \"store default plan config\", func(tx *sqlx.Tx) error {\n    if err := StoreDefaultPlanConfig(userId, config, tx); err != nil {\n        return fmt.Errorf(\"store default plan config for %s: %w\", userId, err)\n    }\n    return nil\n})\nif err != nil { return err } // tx rolled back safely","preventionTips":["Always invoke via WithTx so tx lifetime/rollback is managed","Return immediately on the first error inside a transaction; never reuse a failed tx","Respect ctx cancellation — canceling the context aborts the tx mid-statement","Check RowsAffected to catch zero-row updates on unknown userIds"],"tags":["database","postgres","transaction","update","go"],"backgroundTag":"transaction-aborted","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}