{"record":{"id":"3a2e9398416c04f2","repo":"plandex-ai/plandex","slug":"error-creating-invite-v","errorCode":null,"errorMessage":"error creating invite: %v","messagePattern":"error creating invite: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/invite_helpers.go","lineNumber":16,"sourceCode":"package db\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/jmoiron/sqlx\"\n)\n\nfunc CreateInvite(invite *Invite, tx *sqlx.Tx) error {\n\terr := tx.QueryRow(\"INSERT INTO invites (org_id, email, name, inviter_id, org_role_id) VALUES ($1, $2, $3, $4, $5) RETURNING id\", invite.OrgId, invite.Email, invite.Name, invite.InviterId, invite.OrgRoleId).Scan(&invite.Id)\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating invite: %v\", err)\n\t}\n\n\treturn nil\n}\n\nfunc GetInvite(id string) (*Invite, error) {\n\tvar invite Invite\n\terr := Conn.Get(&invite, \"SELECT * FROM invites WHERE id = $1\", id)\n\n\tif err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"error getting invite: %v\", err)\n\t}\n\n\treturn &invite, nil","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/invite_helpers.go#L1-L34","documentation":"CreateInvite inserts a row into the invites table inside an existing transaction and scans the RETURNING id back into invite.Id. When the INSERT fails (constraint violation, FK violation, bad column, connection loss), the raw driver error is wrapped with this message. The error is wrapped with %v so the underlying pq/pg error text is preserved but not typed.","triggerScenarios":"tx.QueryRow(\"INSERT INTO invites ... RETURNING id\").Scan fails: org_id or inviter_id or org_role_id references a nonexistent row, duplicate invite (unique constraint if defined), invalid NULL in a NOT NULL column (e.g. empty Email/Name), transaction already aborted by a prior error, or DB connection dropped mid-statement.","commonSituations":"InviteUserHandler submitting a payload with an empty email or an org_role_id belonging to another org, seeding data against a stale schema migration, or calling CreateInvite with a nil/expired transaction after an earlier statement in the same tx failed.","solutions":["Inspect the wrapped cause with errors.As on *pq.Error / *pgconn.PgError to distinguish constraint violation (code 23505/23503) from connection failure.","Verify invite.OrgId, invite.InviterId, and invite.OrgRoleId exist in their tables before inserting.","Validate Email and Name are non-empty at the handler layer to avoid NOT NULL violations.","Check that the invites table schema/migrations match the five columns in the INSERT.","Ensure the transaction is still valid — don't reuse a tx after a previous statement in it failed."],"exampleFix":"// before\nif err != nil {\n    return fmt.Errorf(\"error creating invite: %v\", err)\n}\n\n// after\nif err != nil {\n    var pgErr *pq.Error\n    if errors.As(err, &pgErr) && pgErr.Code == \"23503\" {\n        return fmt.Errorf(\"invite references missing org/user/role: %w\", err)\n    }\n    return fmt.Errorf(\"error creating invite: %w\", err)\n}","handlingStrategy":"validation","validationCode":"func validateInvite(inv *db.Invite) error {\n    if inv == nil || inv.OrgId == \"\" || inv.Email == \"\" || inv.InviterId == \"\" || inv.OrgRoleId == \"\" {\n        return errors.New(\"invite missing required fields\")\n    }\n    if _, err := mail.ParseAddress(inv.Email); err != nil {\n        return fmt.Errorf(\"invalid email: %w\", err)\n    }\n    return nil\n}","typeGuard":"func isPGError(err error) (*pq.Error, bool) {\n    var pgErr *pq.Error\n    if errors.As(err, &pgErr) {\n        return pgErr, true\n    }\n    return nil, false\n}","tryCatchPattern":"if err := db.CreateInvite(invite, tx); err != nil {\n    if pgErr, ok := isPGError(err); ok {\n        switch pgErr.Code {\n        case \"23503\":\n            return fmt.Errorf(\"org/inviter/role not found: %w\", err)\n        case \"23505\":\n            return fmt.Errorf(\"duplicate invite: %w\", err)\n        }\n    }\n    return fmt.Errorf(\"create invite: %w\", err)\n}","preventionTips":["Always validate required fields and email format before creating invites.","Ensure org, inviter, and role ids exist (and belong to the same org) before insert.","Keep DB migrations in sync with the code's expected schema.","Never reuse a sqlx.Tx after one of its statements has failed.","Use %w instead of %v when wrapping so callers can errors.As into driver error types."],"tags":["database","sql","insert","foreign-key","transaction"],"backgroundTag":"database-constraint-violation","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"}