* Show the window at once while SolidCraft starts (#1210) The window stayed hidden until the whole setup had run (eframe shows it after the first painted frame), and building the 3D view's pipelines ran on the window's thread: seconds with nothing on screen on some computers, then a window that could not be moved or minimized. The first frame now paints a light starting page (the name, a progress bar, the step being done; solidcraft_ui_egui::starting), in the saved language and interface font, and the setup runs behind it, a step a frame. The pipelines and the anti-aliasing check are built on a worker (viewport_egui::build, SolveApp::build_wgpu_split) and adopted the frame after (SolveApp::adopt_wgpu), keeping the tessellation shader's own background compile. If the worker fails, the view says it cannot draw the model and how safe mode can; closing the app waits for a compile still running. A minimized or occluded window runs the remaining steps at once. Closing the window from the starting page is not a failed start; a close after a lost device still is. The app counts as started once every step is done. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Starting page: format, and its tests install the message catalogs Each test runs in a process of its own in CI, so the page's tests install the catalogs themselves before reading their labels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
10 KiB
Crash reports
When the desktop app crashes or hits an internal error, it writes a crash report on this computer. Each report holds enough to reproduce and fix the problem: in most cases the design and the exact commands that trigger it. Reports are never sent anywhere. To share one, use Report… in Help ▸ Crash Reports…, which opens a GitHub issue draft. Nothing is shared until you review and submit it, and the design is not part of the draft.
To send a report:
- Review the title, report text and screenshot in SolidCraft, then click Open GitHub issue form (Open GitHub in narrow windows). SolidCraft copies the report text to your clipboard and opens GitHub. Short reports are also filled in through the URL; paste longer reports into the GitHub draft.
- Attach the screenshot if you want to share it: use Copy screenshot and paste it into GitHub, or use Save screenshot… and upload the PNG. Screenshots are not attached automatically.
- Click Submit new issue on GitHub to publish the report. Opening the draft alone does not send it.
Submission and fallback behavior
The same reviewed report dialog is used by Report a bug, command errors and crash reports. Desktop and web builds submit through GitHub in the browser; the dialog has no direct submission API and needs no GitHub token in SolidCraft. It explains this beside the public-report/account notice. Sign in with a GitHub account to publish the report.
Copy report and Open GitHub issue form remain available without credentials or a connection. Copying works even before the required description is filled in; opening GitHub with an empty description instead focuses that field and explains what is missing. Neither action closes the draft. On narrow windows the footer uses Open GitHub and Copy report; close the draft with the header's close button. The two export actions must remain visible at high UI zoom.
If offline, a browser launch is blocked, or GitHub cannot be reached, the dialog tells the user to copy the report and keep the text to submit later. Opening GitHub requests a clipboard copy even for short reports. SolidCraft cannot confirm browser launch, clipboard delivery or submission; the draft stays editable for retrying. Copying or opening a report does not modify the design or its undo history.
Where they are
<data dir>/solidcraft/crashes/, next to the recovery folder:
| System | Folder |
|---|---|
| Linux | ~/.local/share/solidcraft/crashes (or $XDG_DATA_HOME/solidcraft/crashes) |
| Windows | %LOCALAPPDATA%\SolidCraft\crashes |
| macOS | ~/Library/Application Support/SolidCraft/crashes |
SOLIDCRAFT_CRASH_DIR overrides the folder. solidcraft --crash-log and
solidcraft-cli crashes dir print it.
For agents
All of these read the same folder:
| From | List | One report | Delete |
|---|---|---|---|
Engine command (MCP execute, control channel, scripts) |
diagnostics.crash_reports {limit?} |
diagnostics.crash_report {id} |
diagnostics.crash_reports.clear {id?} |
| MCP tool | crash_reports {limit?} |
crash_reports {id} |
— |
| CLI | solidcraft-cli crashes [--json] |
solidcraft-cli crashes show <id> |
solidcraft-cli crashes clear [<id>] |
| Control channel (UI) | ui.help {"item": "crashes"} opens the window |
Reproduce: solidcraft-cli crashes replay <id> opens the report's design, runs its
commands, and reports whether the same internal error happens again (same place and message).
Without the CLI, run solidcraft-cli run <report>/replay.json --in <report>/design.sc.
A fixed crash turns into a regression test with the same two files.
Check that reporting works: with SOLIDCRAFT_CRASH_TEST=1 set for the app, the command
diagnostics.crash_test has these modes:
panic: an internal error in a commandkernel: an internal error inside the geometry kernelworker: an internal error on a Rayon worker inside the geometry kernel (caught; reported with the command, recovered)worker_raw: an internal error on a Rayon worker outside the kernel guard (caught as a command panic)abort: the app ends at once, and the report appears at the next start. On macOS the signal handler catches it, so the report names SIGABRT and the frames that calledabort().
A panic on a Rayon worker during a command is held and reported with that command when it
ends. Two limits: only Rayon pool threads are held, so a panic on a plain thread
(solidcraft-each, solidcraft-interference, plan-mesh) is written at once from the
journal, not with the design the command started from; and the count of open commands is
process-wide, so a worker panic from unrelated background work while a command is open is
reported with the next command that ends.
What a report holds
A folder crashes/<YYYYMMDD-HHMMSS>-<signature>/:
report.json("format": "solidcraft-crash/1"):kind: one ofcommand_panic: a command hit an internal error; it was caught and the design was left unchangedkernel_panic_recovered: the third-party geometry kernel panicked and was caught. This is harmless on the desktop, but it would crash the web build. A panic on a Rayon worker during a command is recorded this way, with that command and design, when the worker was inside the kernel guard or the command fails with a kernel error.panic: an internal error outside any command. A Rayon worker panic while no command is running is still this kind, written at once.unclean_exit: a previous session ended without recording a clean exit. It is detected at the next start, which may be days later. Possible causes include an abort, a stack overflow, a segfault, a crash inside a graphics driver, a system shutdown, or the process being forcibly stopped. This kind alone does not identify the cause. When the app died while starting up, the message andlocationname the startup step (see below). On Windows and macOS, a captured native crash also says the exception or signal, the module it happened in and the offset into it.
message,location(file:line),threadbacktrace: framessymbol (file:line), without the panic machinery, std internals or the user's home folderapp(version, commit, build date),system(OS, architecture, renderer and GPU),session.uptime_scommand: the command that crashed, with its parametersrecent_commands: up to 32, with ok or errorbase: what the replay starts from (the design before the command, an autosave, a saved file or a new design)count: how many matching reports have been recorded; repeats update the existing report.first_seen,last_seen: UTC timestamps when the report was first and most recently recorded. Forunclean_exit, these are detection times at a later launch, not the exact times the sessions ended. The session start inmessagemay be much earlier; the report does not imply a failure in the currently open design.notes: what is missing and why, for example a design too large to copystartup_phase:{step, ms}when the app died before it was up: the step it was in (window,graphics instance,window surface,adapter request,adapter chosen,device creation,egui renderer (shader compile),surface configure,app setup,first frame (present), which shows the window with its starting page, then the setup run behind that page:viewport pipelines (shader compile),design,recovery,first frame) and how many milliseconds after launch it began.system.environmentnames the renderer (backend, GPU, driver) as soon as the adapter is picked, so it is there even when the device never started.native(Windows and macOS): what the native crash handler caught:code,name,address(of the faulting instruction),module,offset(into the module),detail(for an access violation or a segfault, the address read or written) andthread. Thebacktracethen shows the same in two lines.- On macOS, where a signal handler catches SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP and SIGABRT,
codeandsignalare the signal's name (SIGSEGV),namesays it in words (segmentation fault, orstack overflowwhen the fault is just below the thread's stack), and it addssi_code,thread_name,pidandframes: up to 24module+offset symbol+offsetlines walked up the frame pointers from the faulting instruction, which thebacktracelists too. The process still ends with the signal, so macOS also writes its own crash report, with every thread's stack:~/Library/Logs/DiagnosticReports/solidcraft-<date>.ips(Console ▸ Crash Reports), whosepidis the one innative.
- On macOS, where a signal handler catches SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP and SIGABRT,
design.sc: the design the replay starts fromreplay.json:{"commands": [{command, params}, …]}minidump.dmp(Windows, native crashes; on macOS, see the system's own report above): the threads' stacks and the loaded modules at the crash, for WinDbg or Visual Studio. It holds stack memory only, not the design, but it stays on this computer like the rest of the report; share it only on request.
A crash that ends the process without any exception (a fail-fast, which is how an abort ends on
Windows) still gets the startup step. Windows can also keep its own dumps of every crash: set
DumpFolder under HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps.
How it stays cheap and small
-
Before a crash: the app keeps a journal of the top-level commands run on the design on screen (
crashes/sessions/*.jsonl, at most 512 KB). Each command adds two small writes, with no flush to disk. Previews and other scratch sessions are not recorded. Each autosave restarts the journal from the autosaved design. A clean exit deletes it. The journal file is locked while its app runs, so at the next start, a journal nobody holds belongs to an app that died. -
A panic captures its backtrace only the first time its signature is seen. The signature is the place plus the message, with numbers ignored.
-
Limits:
- at most 5 new reports per run
- 20 reports
- 50 MB in total
- 90 days
- a design over 10 MB is not copied; the report notes that
When over a limit, recovered kernel panics are deleted before real crashes, and the oldest first.
-
Where it's off: the CLI, tests and the web build never install the hook. There, commands pay only a check of one atomic flag.
Release builds keep line tables (debug = "line-tables-only"), so backtraces name the file
and line. Stripping a binary (strip) removes them, and the function names too.