Claude screenshot crashes Hise
-
@Christoph-Hart Seems to happen a lot more since the last commits
CLAUDE:
HISE 4.9.3 (102de5c4) — recurrent SIGABRT via the REST API screenshot endpoints
Symptom. HISE dies with
Abort trap: 6.
8 of the 33 crash reports on this machine (2026‑08‑19 → 2026‑08‑23) have byte‑identical stacks:std::terminate() → juce::MessageQueue::runLoopSourceCallback(void*) → __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ → …i.e. something escapes a MessageManager::callAsync callback. The stack is already unwound, so the report names no culprit — which is why this has been hard to pin down.
Correlation. Every occurrence I could attribute happened during
GET /api/testing/screenshot. Two crashes today were directly on that call; two earlier sessions logged500 — /api/testing/screenshot?moduleId=Interface&outputPath=…shortly before dying. It hits both the cropped (&id=) and the plainmoduleId‑only form.Root cause (
hi_backend/backend/ai_tools/RestHelpers.cpp:2539).SafeAsyncCall::callAsyncIfNotOnMessageThread<...>(*sp, [&](...) // fire-and-forget { hise::ScriptContentComponent component(&spp); capturedImage = component.createComponentSnapshot(cropBounds, true, scale); captureSuccess = capturedImage.isValid(); captureComplete.signal(); }); if (!captureComplete.wait(1000)) return req->fail(500, "screenshot capture timed out"); // ← stack frame dies herecallAsyncIfNotOnMessageThreadisMessageManager::callAsync(MiscToolClasses.h:87) — it does not wait. The lambda capturescapturedImage,captureSuccessandcaptureCompleteby reference off the REST thread's stack. When the message thread takes longer than 1000 ms, the handler returns, that frame is destroyed, and the lambda then writes into freed stack memory and signals a destroyedWaitableEvent. Hence: 500 first, abort shortly after.1000 ms is easy to blow — the lambda constructs a fresh
ScriptContentComponentand paints every script component, including all custom paint routines, on a 1600×900 interface.Same pattern, two more sites:
RestHelpers.cpp:2725(testing/e2e, 30 s) and:6508(dsp/screenshot, 1500 ms — and that lambda spends 500 ms inrunDispatchLoopUntilbefore capturing, re-entering the message loop).Suggested fix.
SafeAsyncCall::callAsyncAndWaitalready exists in the same header (MiscToolClasses.h:104) and is documented to return false on timeout/deletion. Failing that: heap‑allocate the shared state in aReferenceCountedObject/shared_ptrcaptured by value, so a timed‑out request cannot outlive it. Atry/catcharound the lambda body would also convert the abort into a 500.
Two caveats so you can present it accurately: the other 5 SIGABRTs I can't attribute to the screenshot endpoint from the crash file alone — the unwound stack gives nothing. And the dangling-frame mechanism is provable from the code and matches the 500-then-crash sequence, but I couldn't confirm which exception actually terminates, only that one escapes a message-thread callback.
-
@ustk what's a Claude screenshot?
-
@David-Healey When Claude makes modifications on UI, it makes a screenshot using the interaction test window to see if it renders as it should