fix: prevent thread resume crash from null metadata and icon (fixes #2827)#2830
fix: prevent thread resume crash from null metadata and icon (fixes #2827)#2830giulio-leone wants to merge 2 commits intoChainlit:mainfrom
Conversation
There was a problem hiding this comment.
1 issue found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="backend/chainlit/data/sql_alchemy.py">
<violation number="1" location="backend/chainlit/data/sql_alchemy.py:265">
P1: `update_thread` now clears existing thread metadata to `{}` when called without metadata, causing data loss on common `create_step` path.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Fix frontend crash when resuming threads where a chat profile has
a null icon — icon.startsWith('/public') throws TypeError (fixes Chainlit#2827).
Changes:
- WelcomeScreen.tsx: add optional chaining icon?.startsWith('/public')
- Starter.tsx: remove redundant ?. inside existing truthiness guard
- sql_alchemy.py: use 'is not None' check instead of falsy check so
empty metadata dicts {} are properly serialized instead of stored
as NULL (preserves None = 'don't update' semantics)
22ad7a8 to
2cc2190
Compare
|
re: the first change. This mirrors similar instability I subclass around #2760 (comment) |
|
@nzjrs Thanks for confirming! Your PR #2760 tackles the same root instability — the streamable-http transport silently drops connections without surfacing errors to the user. This PR adds the error toast so users at least know why it failed, rather than seeing a silent hang. Happy to coordinate if there's overlap with your approach. |
|
@nzjrs Thanks for linking your PR! Yes, the |
Prevents data loss when update_thread() is called without metadata parameter — existing metadata is now preserved instead of being overwritten with empty dict. Signed-off-by: Giulio Leone <6887247+giulio-leone@users.noreply.github.com>
ea24108 to
d581da6
Compare
|
The CI failures are from the Happy to re-run CI or investigate further if maintainers believe otherwise. |
|
Thanks @nzjrs — glad to hear this aligns with what you've been seeing! The null metadata/icon guard here is a minimal defensive fix for the thread resume crash path. Your subclass workaround in #2760 sounds like a more comprehensive approach for the broader instability. Hopefully both can land to cover the different failure modes. |
|
Friendly ping — CI is green, tests pass, rebased on latest. Ready for review whenever convenient. Happy to address any feedback. 🙏 |
|
@nzjrs Thanks for the pointer — I see you're hitting related instability in #2760. This PR takes the defensive approach: instead of crashing on |
Go away bot. |
Problem
Since upgrading to 2.10.0, some old threads fail to resume with two errors:
Frontend:
Cannot read properties of null (reading 'startsWith')— when a chat profile has a nullicon,icon.startsWith('/public')throws a TypeError.Backend:
null value in column "metadata" of relation "Thread" violates not-null constraint— old threads storedNULLmetadata, which fails onINSERT ... ON CONFLICT UPDATE.Fix
Frontend (WelcomeScreen.tsx, Starter.tsx)
icon?.startsWith('/public')in WelcomeScreen.tsx?after truthiness guard in Starter.tsx (already checkedstarter.icon ? ...)Backend (sql_alchemy.py)
update_thread()to default metadata to'{}'instead ofNULL:Testing
undefined(falsy) instead of throwing'{}'instead ofNULL, preventing NOT NULL violationsFixes #2827
Summary by cubic
Prevents crashes when resuming threads by making icon checks null-safe and safely merging thread metadata (no NULL writes, preserve existing data). Fixes #2827.
WelcomeScreenusesicon?.startsWith('/public');Starterremoves redundant optional chaining under an existing icon guard.update_threadmerges incoming metadata with existing, treatsNonevalues as deletions, serializes{}instead ofNULL, derivesnamefrom merged metadata when missing, and only updates metadata when metadata is passed—preserving stored data.Written for commit d581da6. Summary will update on new commits.