Skip to content

Bug: Handle Metal/llama-cpp SIGABRT crash on app quit gracefully #863

Description

@malibio

Problem

Two related issues when closing/quitting the NodeSpace app:

Issue 1: Window close button (red X) doesn't work

Clicking the macOS window close button logs this error and fails to close:

[Debug] [AppInit] Tauri window close requested - flushing pending operations...
[Error] Unhandled Promise Rejection: window.destroy not allowed. Permissions associated with this command: core:window:allow-destroy

The window.destroy() call is blocked by Tauri's permission system.

Issue 2: SIGABRT crash on app quit

When quitting the app (Cmd+Q or menu), a SIGABRT crash occurs in the ggml Metal backend during cleanup:

Exception Type:    EXC_CRASH (SIGABRT)
Exception Codes:   0x0000000000000000, 0x0000000000000000

Termination Reason:  Namespace SIGNAL, Code 6, Abort trap: 6
Terminating Process: nodespace-app [14836]

Application Specific Information:
abort() called

Crash Stack Trace (Key Frames)

0   libsystem_kernel.dylib    __pthread_kill + 8
1   libsystem_pthread.dylib   pthread_kill + 296
2   libsystem_c.dylib         abort + 124
3   nodespace-app             ggml_abort + 160
4   nodespace-app             ggml_metal_rsets_free + 152
5   nodespace-app             ggml_metal_device_free + 24
6   nodespace-app             std::__1::unique_ptr<ggml_metal_device, ggml_metal_device_deleter>::~unique_ptr
7   libsystem_c.dylib         __cxa_finalize_ranges + 480
8   libsystem_c.dylib         exit + 44
9   nodespace-app             std::sys::pal::unix::os::exit
10  nodespace-app             std::process::exit
11  nodespace-app             nodespace_app_lib::run::{{closure}}

Root Cause

The crash occurs during the __cxa_finalize_ranges (C++ cleanup) phase when the app exits. The ggml_metal_device destructor calls ggml_metal_rsets_free which then calls ggml_abort().

This appears to be a known issue with llama.cpp's Metal backend where GPU resources aren't properly released before the app terminates, causing an assertion failure during cleanup.

Environment

  • macOS 26.2 (25C56)
  • Apple Silicon (Mac16,8)
  • Metal GPU backend enabled
  • Tauri 2.0 + Rust

Acceptance Criteria

Window Close Button

  • Add core:window:allow-destroy permission to Tauri capabilities
  • Window closes properly when clicking the red X button
  • Pending operations are flushed before window destruction

Metal/llama-cpp Crash

  • Investigate proper shutdown sequence for llama.cpp/mistral.rs Metal backend
  • Implement graceful cleanup of GPU resources before app exit
  • Ensure ggml_metal_device_free is called explicitly during Tauri's on_exit or before_exit event
  • No crash report generated on normal app quit
  • Document the shutdown sequence in code comments

Technical Notes

Window Permission Fix

Add to src-tauri/capabilities/default.json:

{
  "permissions": [
    "core:window:allow-destroy",
    // ... existing permissions
  ]
}

Metal Crash Solutions

  1. Explicit cleanup before exit: Call llama.cpp cleanup functions explicitly in Tauri's RunEvent::Exit handler before std::process::exit() is called

  2. Graceful shutdown signal: Use a shutdown signal to tell the AI service to release Metal resources before the app exits

  3. Avoid static destruction order issues: The crash happens during __cxa_finalize_ranges which suggests static destruction order issues - may need to use explicit cleanup instead of RAII destructors for Metal resources

Related Code

  • Window close handler: Check src/lib/services/app-init.ts for the close request handler
  • Tauri capabilities: src-tauri/capabilities/default.json
  • The crash originates from nodespace_app_lib::run::{{closure}} which handles Tauri events

References

Metadata

Metadata

Assignees

Labels

backendbugSomething isn't working

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions