{"record":{"id":"8353aa10d701fd91","repo":"FlowiseAI/Flowise","slug":"unhandled-edge-case","errorCode":null,"errorMessage":"Unhandled Edge Case","messagePattern":"Unhandled Edge Case","errorType":"exception","errorClass":"InternalFlowiseError","httpStatus":400,"severity":"error","filePath":"packages/server/src/IdentityManager.ts","lineNumber":465,"sourceCode":"                newPlanId === process.env.CLOUD_PRO_ID\n            ) {\n                loggedInUser.activeOrganizationProductId = newPlanId\n            }\n\n            req.user = {\n                ...req.user,\n                ...loggedInUser\n            }\n\n            // Update passport session\n            // @ts-ignore\n            req.session.passport.user = {\n                ...req.user,\n                ...loggedInUser\n            }\n\n            req.session.save((err) => {\n                if (err) throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, GeneralErrorMessage.UNHANDLED_EDGE_CASE)\n            })\n\n            return {\n                status: 'success',\n                user: loggedInUser\n            }\n        }\n        return {\n            status: 'error',\n            message: 'Payment or subscription update not completed'\n        }\n    }\n\n    public async createStripeUserAndSubscribe({ email, userPlan, referral }: { email: string; userPlan: UserPlan; referral?: string }) {\n        if (!this.stripeManager) {\n            throw new Error('Stripe manager is not initialized')\n        }\n","sourceCodeStart":447,"sourceCodeEnd":483,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/server/src/IdentityManager.ts#L447-L483","documentation":"Thrown inside the req.session.save callback in updateSubscriptionPlan() as an InternalFlowiseError (HTTP 400, UNHANDLED_EDGE_CASE) when Express saves the session and returns an error. It fires after a successful Stripe plan update when persisting the new user/subscription data back into the passport session fails (e.g. session store unreachable). Note: because the throw occurs inside the async callback of session.save, it will not be caught by the surrounding async function's try/catch or converted to a rejected promise — it will likely surface as an uncaught exception, so callers cannot rely on normal await-based error handling.","triggerScenarios":"The session store (Redis/MemoryStore/DB) is down or errors during save after a plan change; the session payload exceeds the store size limit; a serialization error in passport; the connection to the session store dropped mid-request. Because the throw is in the callback, it typically becomes an uncaughtException rather than a route-level error.","commonSituations":"Redis session store outage; MemoryStore used in production (not designed for it) and hitting limits; network blip to a remote session store; concurrent requests mutating the same session.","solutions":["Check session store health (Redis connectivity / DB) and capacity; restart or scale the store.","Ensure the session store client (e.g. connect-redis) is configured with reconnect/error handling and adequate timeouts.","Do not use MemoryStore in production — it leaks and is not fault-tolerant.","Refactor the session.save call into a Promise and await it so errors propagate to the route's error handler instead of becoming uncaught."],"exampleFix":"// before (throw inside callback — escapes async error handling)\nreq.session.save((err) => {\n    if (err) throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, GeneralErrorMessage.UNHANDLED_EDGE_CASE)\n})\n\n// after (promisify so the error is awaitable and reaches the error handler)\nawait new Promise<void>((resolve, reject) => {\n    req.session.save((err) => {\n        if (err) reject(new InternalFlowiseError(StatusCodes.BAD_REQUEST, GeneralErrorMessage.UNHANDLED_EDGE_CASE))\n        else resolve()\n    })\n})","handlingStrategy":"try-catch","validationCode":"// Health-check the session store at boot; surface readiness only when it is reachable\n// e.g. for connect-redis: await redisClient.ping() before listening for traffic","typeGuard":null,"tryCatchPattern":"// The current code throws inside the session.save callback, so a normal\n// try/catch around the call will NOT catch it. Promisify the save first:\ntry {\n    await new Promise<void>((resolve, reject) => {\n        req.session.save((err) =>\n            err ? reject(new InternalFlowiseError(StatusCodes.BAD_REQUEST, GeneralErrorMessage.UNHANDLED_EDGE_CASE)) : resolve()\n        )\n    })\n} catch (e) {\n    return res.status(503).json({ message: 'Session could not be persisted' })\n}","preventionTips":["Promisify req.session.save and await it so errors reach the route's error handler instead of becoming uncaught.","Use a production-grade session store (Redis) with reconnect handling; never MemoryStore in prod.","Monitor session store health and capacity; alert on save errors.","Add a process-level uncaughtException handler that logs session-save failures for visibility."],"tags":["session","authentication","express","error-handling","infrastructure"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}