{"record":{"id":"ca7baa4e53fd5308","repo":"plandex-ai/plandex","slug":"error-adding-org-membership-v","errorCode":null,"errorMessage":"error adding org membership: %v","messagePattern":"error adding org membership: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/org_helpers.go","lineNumber":124,"sourceCode":"\tif err != nil {\n\t\tif IsNonUniqueErr(err) {\n\t\t\t// Handle the uniqueness constraint violation\n\t\t\treturn nil, fmt.Errorf(\"an org with domain %s already exists\", *domain)\n\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"error creating org: %v\", err)\n\t}\n\n\torgOwnerRoleId, err := GetOrgOwnerRoleId()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting org owner role id: %v\", err)\n\t}\n\n\t_, err = tx.Exec(\"INSERT INTO orgs_users (org_id, user_id, org_role_id) VALUES ($1, $2, $3)\", org.Id, userId, orgOwnerRoleId)\n\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error adding org membership: %v\", err)\n\t}\n\n\treturn org, nil\n}\n\nfunc GetOrgForDomain(domain string) (*Org, error) {\n\tvar org Org\n\tquery := fmt.Sprintf(\"SELECT %s FROM orgs WHERE domain = $1\", orgFields)\n\terr := Conn.Get(&org, query, domain)\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 org for domain: %v\", err)\n\t}\n","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/org_helpers.go#L106-L142","documentation":"CreateOrg wraps a failure inserting the owner's row into orgs_users into 'error adding org membership: %v'. The org was created but linking the owner with the owner role failed, leaving the transaction to roll back.","triggerScenarios":"tx.Exec('INSERT INTO orgs_users ...') fails: invalid org_role_id (foreign key violation 23503), org_user_unique conflict, connection drop, or aborted transaction.","commonSituations":"Role-id lookup returned a stale/incorrect id violating the FK to org_roles; concurrent creation raced on the same user/org pair; connection reset inside a long transaction.","solutions":["Check the wrapped %v for a 23503 FK violation and verify GetOrgOwnerRoleId returned a valid org_roles.id","Rely on the transaction rollback: the partial org row is not committed, so simply retry after fixing the cause","For concurrent self-insert races, add ON CONFLICT ON CONSTRAINT org_user_unique DO NOTHING like AddOrgDomainUsers does","Verify the DB connection is stable for multi-statement transactions (pool settings, timeouts)"],"exampleFix":"// before\n_, err = tx.Exec(\"INSERT INTO orgs_users (org_id, user_id, org_role_id) VALUES ($1, $2, $3)\", org.Id, userId, orgOwnerRoleId)\n// after\n_, err = tx.Exec(\"INSERT INTO orgs_users (org_id, user_id, org_role_id) VALUES ($1, $2, $3) ON CONFLICT ON CONSTRAINT org_user_unique DO NOTHING\", org.Id, userId, orgOwnerRoleId)","handlingStrategy":"try-catch","validationCode":"orgOwnerRoleId, err := db.GetOrgOwnerRoleId()\nif err != nil { return err } // resolve before insert\n// optionally pre-check membership\nok, _ := db.ValidateOrgMembership(userId, orgId)","typeGuard":null,"tryCatchPattern":"org, err := db.CreateOrg(req, userId, &domain, tx)\nif err != nil {\n    var pqErr *pq.Error\n    if errors.As(err, &pqErr) && pqErr.Code == \"23503\" {\n        return fmt.Errorf(\"invalid role/org reference: %s\", pqErr.Detail)\n    }\n    return err\n}","preventionTips":["Use ON CONFLICT DO NOTHING on orgs_users inserts for idempotency","Keep the whole CreateOrg flow in one tx so partial orgs roll back","Validate role ids against org_roles before insert","Watch connection stability for multi-statement transactions"],"tags":["database","postgresql","foreign-key","transaction"],"backgroundTag":"foreign-key-constraint-violation","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"}