Skip to content

fix: stale urlId on first save, action-runner abort race, and stuck spinner on interrupted file actions - #2188

Open
Cadenadb wants to merge 3 commits into
stackblitz-labs:mainfrom
Cadenadb:fix/urlid-closure-and-abort-race
Open

fix: stale urlId on first save, action-runner abort race, and stuck spinner on interrupted file actions#2188
Cadenadb wants to merge 3 commits into
stackblitz-labs:mainfrom
Cadenadb:fix/urlid-closure-and-abort-race

Conversation

@Cadenadb

@Cadenadb Cadenadb commented Aug 5, 2026

Copy link
Copy Markdown

Summary

Three small, independent bug fixes found while debugging a real interrupted-generation scenario (an LLM response cut off mid-file). Each is reproducible on current main and verified against a live deployment.

1. app/lib/persistence/useChatHistory.ts — stale closure on first save

When a new chat's first urlId is generated (storeMessageHistory), it's assigned to a local _urlId and to React state via setUrlId(urlId), but the setMessages(...) call that actually persists the chat still reads the old urlId closure variable, which is still undefined at that point. The chat gets saved with urlId: undefined and never becomes reachable from the sidebar again (history list filters on item.urlId && item.description), even though the chat and its messages are otherwise saved correctly. One-word fix: use _urlId (the value just computed a few lines above) instead of urlId in that call.

2. app/lib/runtime/action-runner.ts — abort() undone by an already-queued execution

Calling action.abort() sets status: 'aborted', but runAction() had already chained a call onto #currentExecutionPromise before the abort happened. That queued #executeAction() runs on a later microtask and unconditionally does this.#updateAction(actionId, { status: 'running' }) at its start, silently overwriting the abort. Fixed two ways: abort() now also sets executed: true (so runAction()'s existing if (action.executed) return; guard prevents any future re-queue), and #executeAction() now checks action.abortSignal.aborted before doing anything, so an already-queued execution can no longer clobber an abort that happened in between.

3. app/components/chat/Artifact.tsx — spinner never resolves for an interrupted file action

If a response gets cut off mid-file (token limit, dropped connection, client crash), the corresponding <boltAction type="file"> never gets its closing tag, so it never receives the event that would flip it to 'complete'. The action list then shows a spinner for that file forever, even after reload, even with no generation active — nothing is actually running, but the UI can't tell. Rather than trying to catch every code path that can leave an action in this state, this fixes it at render time: ActionList now reads the existing streamingState store, and a 'file' action stuck at pending/running is shown as aborted once nothing is actually streaming. 'start'/'shell' actions are intentionally excluded, since those can legitimately keep running well after the text stream ends (e.g. a real in-progress npm install).

Testing

All three verified on a real fork deployment against a chat where generation was genuinely interrupted mid-file (frozen tab). Confirmed: (a) the affected chat becomes reachable from history again on new chats, (b) the abort no longer gets silently reverted, (c) the file action correctly shows as aborted instead of spinning forever, with no change in behavior for actions that complete normally or for shell/start actions that are still genuinely running.

Scope

Deliberately minimal and independent from each other -- no unrelated refactors, no changes to files outside these three.

@Cadenadb Cadenadb changed the title Fix stale urlId on first save, action-runner abort race, and stuck spinner on interrupted file actions fix: stale urlId on first save, action-runner abort race, and stuck spinner on interrupted file actions Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant