{"record":{"id":"2799e8c82c9dc57b","repo":"plandex-ai/plandex","slug":"error-getting-default-plan-config-v-2799e8","errorCode":null,"errorMessage":"error getting default plan config: %v","messagePattern":"error getting default plan config: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/plan_helpers.go","lineNumber":30,"sourceCode":"\t\"strconv\"\n\t\"time\"\n\n\tshared \"plandex-shared\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/jmoiron/sqlx\"\n\t\"github.com/lib/pq\"\n\t\"github.com/sashabaranov/go-openai\"\n)\n\nfunc CreatePlan(ctx context.Context, orgId, projectId, userId, name string) (*Plan, error) {\n\tvar plan *Plan\n\terr := WithTx(ctx, \"create plan\", func(tx *sqlx.Tx) error {\n\n\t\tplanConfig, err := GetDefaultPlanConfig(userId)\n\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting default plan config: %v\", err)\n\t\t}\n\n\t\tquery := `INSERT INTO plans (org_id, owner_id, project_id, name, plan_config) \n\tVALUES ($1, $2, $3, $4, $5)\n\tRETURNING id, created_at, updated_at`\n\n\t\tplan = &Plan{\n\t\t\tOrgId:      orgId,\n\t\t\tOwnerId:    userId,\n\t\t\tProjectId:  projectId,\n\t\t\tName:       name,\n\t\t\tPlanConfig: planConfig,\n\t\t}\n\n\t\terr = tx.QueryRow(\n\t\t\tquery,\n\t\t\torgId,\n\t\t\tuserId,","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/plan_helpers.go#L12-L48","documentation":"Inside CreatePlan's WithTx callback, an error from GetDefaultPlanConfig(userId) is re-wrapped with this identical message ('error getting default plan config'). It means the new plan's starting config could not be loaded from the user's row — usually because the userId doesn't exist in users (sql.ErrNoRows) — and causes the whole 'create plan' transaction to roll back.","triggerScenarios":"CreatePlan runs with a userId that has no users row, a DB connection failure, or a default_plan_config value that can't scan into shared.PlanConfig; the WithTx('create plan') transaction then rolls back and no plan is created.","commonSituations":"Plan creation triggered by a stale or forged session whose user was deleted; environment where user seed data is missing; corrupted default_plan_config JSON; transient Postgres outage during plan creation.","solutions":["Unwrap the nested cause: 'no rows in result set' means the userId is invalid — verify the user exists/authenticates before CreatePlan","Apply migrations / seed data if users.default_plan_config or the users row is missing","For scan errors, inspect and repair the user's default_plan_config JSON","On transient connection errors, retry CreatePlan after DB health is restored (the tx rolled back cleanly)"],"exampleFix":"// before\nplanConfig, err := GetDefaultPlanConfig(userId)\nif err != nil {\n    return fmt.Errorf(\"error getting default plan config: %v\", err)\n}\n// after: fail fast with a distinct not-found path\nplanConfig, err := GetDefaultPlanConfig(userId)\nif err != nil {\n    if strings.Contains(err.Error(), \"no rows in result set\") {\n        return fmt.Errorf(\"user %s not found: %w\", userId, err)\n    }\n    return fmt.Errorf(\"error getting default plan config: %w\", err)\n}","handlingStrategy":"validation","validationCode":"// verify user exists before CreatePlan\nvar exists bool\nif err := Conn.Get(&exists, \"SELECT EXISTS(SELECT 1 FROM users WHERE id=$1)\", userId); err != nil || !exists {\n    return nil, fmt.Errorf(\"cannot create plan: user %s not found\", userId)\n}","typeGuard":null,"tryCatchPattern":"plan, err := CreatePlan(ctx, orgId, projectId, userId, name)\nif err != nil {\n    if strings.Contains(err.Error(), \"no rows in result set\") {\n        return nil, fmt.Errorf(\"user has no default plan config / not found\")\n    }\n    log.Printf(\"CreatePlan: %v\", err)\n    return nil, err\n}","preventionTips":["Authenticate and resolve the user row before starting plan creation","Give users a default_plan_config at account creation (NOT NULL DEFAULT '{}')","Keep WithTx scopes short to minimize rollback blast radius","Unwrap nested errors with %w and errors.Is for cleaner cause detection"],"tags":["database","postgres","transaction","not-found","go"],"backgroundTag":"record-not-found","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}