Hive Hive
Sign in

fix(cli): HAR recording shutdown crash

GitHub issue · Closed

Metadata
Source
tuist/tuist #11116
Updated
Jun 24, 2026
Domains
CLI
Details

Resolves N/A

This fixes a crash pattern reported from .ips files where the CLI could continue HAR JSON encoding and persistence on detached background tasks while command execution was already completing.

The crash happened because HAR recording was detached and every entry persisted by JSON-encoding and writing network.har from the background task. On the affected GitLab runner, command completion could race those detached tasks, leaving HARRecorder.persist() active while swift_errorInMain was unwinding. This can look customer-specific because it depends on runner timing, macOS scheduling, network activity, and HAR being enabled, so most runs either finish the detached work earlier or exit before the race becomes visible.

The change keeps recording detached so the middleware does not block on HAR work. HARRecorder now owns both detached scheduling and scoped finishing: detached work appends entries to the recorder actor, and the active recorder is finished once at the session boundary to persist entries recorded so far. The recorder closes through a lock-protected state before awaiting actor isolation, so a high-concurrency burst cannot keep shutdown stuck behind a large queue of pending HAR messages. Commands that disable HAR recording temporarily shadow the task-local recorder with nil; commands that keep HAR enabled reuse the existing session recorder instead of creating a nested writer. Any detached recording that arrives after finish() is ignored, which can lose a late HAR entry but prevents JSON encoding and file writes from continuing during shutdown. File upload and download recording now use the same detached recorder API instead of depending on task-local state inside detached tasks.

How to test locally

  • mise run cli:lint --fix
  • tuist generate tuist TuistHAR TuistHARTests ProjectDescription --no-open
  • xcodebuild test -workspace Tuist.xcworkspace -scheme Tuist-Workspace -only-testing TuistHARTests/HARRecordingMiddlewareTests CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY="" COMPILATION_CACHE_ENABLE_CACHING=NO
  • xcodebuild test -workspace Tuist.xcworkspace -scheme Tuist-Workspace -only-testing TuistHARTests/HARRecorderTests -only-testing TuistHARTests/HARRecordingMiddlewareTests CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY="" COMPILATION_CACHE_ENABLE_CACHING=NO
Comments
T
tuist[bot] Jun 5, 2026

🛠️ Tuist Run Report 🛠️

Previews 📦
App Commit Open on device
Tuist 03cbcd3af
Tests 🧪
Scheme Status Cache hit rate Tests Skipped Ran Commit
TuistAcceptanceTests 0 % 0 0 0 a923add3e
TuistApp 0 % 28 0 28 03cbcd3af
TuistUnitTests 0 % 5606 5 5601 0cdddaeee
Failed Tests ❌

Showing 5 of 9 failed tests. See links above for full details.

Flaky Tests ⚠️
  • TuistUnitTests: 3 flaky tests (View all)
Test case Module Suite
parseTestStatuses_returnsPassingModuleNames() TuistXCResultServiceTests XCResultServiceTests
parseTestStatuses_returnsCorrectStatuses() TuistXCResultServiceTests XCResultServiceTests
parseTestXCResult() TuistXCResultServiceTests XCResultServiceTests
Builds 🔨
Scheme Status Duration Commit
TuistAcceptanceTests 4m 27s a923add3e
TuistApp 10m 33s 03cbcd3af
TuistUnitTests 5m 34s 0cdddaeee
Bundles 🧰
Bundle Commit Install size Download size
Tuist 03cbcd3af 19.5 MBΔ -286.2 KB (-1.45%) 14.7 MBΔ -128.4 KB (-0.87%)
P
pepicrft Jun 5, 2026

Addressed both requested changes in a6ab08c4b4:

  • TuistCommand.onError now awaits HARRecorder.finishCurrent() before every terminal exit path in the handler, including the _exit(exitCode) path. That flushes the active task-local recorder before _exit prevents async scope cleanup from running.
  • HARRecorder now uses Synchronization.Mutex<Bool> for the nonisolated finished flag instead of the custom @unchecked Sendable state holder. The early nonisolated close remains, so detached recording tasks can be rejected quickly once shutdown starts.
  • Added HARRecorderTests.finishCurrent_persistsActiveRecorderBeforeTaskLocalScopeExits() to cover explicit flushing of the active task-local recorder before the surrounding scope exits.

Validation:

  • tuist generate tuist TuistHAR TuistHARTests ProjectDescription --no-open
  • xcodebuild test -workspace Tuist.xcworkspace -scheme Tuist-Workspace -only-testing TuistHARTests/HARRecorderTests CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY=""
TA
tuist-atlas[bot] Jun 7, 2026

The fix for the HAR recording shutdown crash is now available in 4.196.1. Update to this version to prevent crashes during command completion.