Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[BUG] FluidMeet: Teams meeting recording exhausts swap and freezes macOS (two hard power-offs required)

Open
#1,137 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
10/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
macos, swift

Research direction

Start with MeetingSessionCoordinator.enqueuePersistence and MeetingSessionStore.atomicPrivateWrite, which the report's stack traces show rewriting the whole session blob on every save. MeetingAutoDetector's reason=busy loop and the ASR model switch in MeetingProcessingPipeline are the other hot spots. Done means reproducing the write volume with a long meeting and showing it drops, which needs a Teams meeting or a simulated session and profiling with Instruments.

Written by the indexing model from the issue text.

Description

Summary

Recording a Microsoft Teams meeting with FluidMeet drove my MacBook into swap exhaustion, forcing me to hard power-off the machine twice in one session. macOS never showed an "out of memory" dialog — instead the kernel suspended FluidVoice for swap exhaustion, then escalated to vm-compressor-space-shortage process kills. The app's own resident footprint was modest (295–397 MB); the damage came from file-backed writes and memory-compressor pressure.

This looks reproducible and appears to be a bug in the fork's session-persistence + model-loading path. Filing here since I don't own the app.

Environment

  • Mac17,3 — Apple Silicon — 24 GB RAM — macOS 26.7.1 (25G241)
  • FluidVoice 1.6.10-beta.7 (26) during the incident; 1.6.12-beta.1 (29) observed later
  • Trigger app: Microsoft Teams (com.microsoft.teams2) — "Fluid Meet" auto-detected and armed

What happened

Attempt App PID Window Outcome
#1 1289 ~19:00 → 19:10 kernel suspended FluidVoice for swap exhaustion → hard power-off
#2 1015 ~19:15 → 19:28 same, then vm-compressor-space-shortage kills → hard power-off

After attempt #2 the kernel killed softwareupdated, assistantd, homed, SafariBookmarksSyncAgent, AccessibilityVisualsAgent, ScreenTimeAgent… Machine only recovered ~19:48.

Evidence — full bundle

📎 All raw evidence (sanitized): https://gist.github.com/arendon1/c8eebbf9658d7d99820166e1fdfb0046

  • 01-Fluid-app.log — full app log (~/Library/Logs/Fluid/Fluid.log)
  • 02-Fluid-app-last2h.log — failure window only
  • 03-kernel-memory-events.txt — kernel memorystatus/jetsam/compressor + ANE events
  • 04-diagnostic-report-excerpts.md — excerpts from the four Apple .diag reports generated in the window
  • 05-RCA.md — full RCA
1. macOS disk-write watchdog exceeded ~4x (.diag, PID 1015)
Writes:    2147.83 MB of file backed memory dirtied over 237 seconds (9066.51 KB/s)
Limit:     2147.48 MB per 86400s
Footprint: 294.52 MB -> 397.42 MB (+102.91 MB in 226s)
Pageins:   103,864 pages
CPU:       90 seconds cpu time over 142 seconds (63% cpu average)

Attempt #1's report shows the same 2147.83 MB but over 40,975 s at 52 KB/s — so the daily write budget was already saturated by long-running use; attempt #2 re-dirtied the same volume in 237 s (~170× faster).

2. Dominant stack = session persistence rewrite — 86/201 samples
MeetingSessionCoordinator.enqueuePersistence(_:)
 └ MeetingSessionStore.save(_:)
   └ MeetingSessionStore.writeSession(_:)
     └ MeetingSessionStore.atomicPrivateWrite(_:to:)
       └ Data.write(to:options:)
         └ writeToFileAux(path:buffer:options:attributes:reportProgress:)
           └ write()

A full-buffer write of the session on every enqueuePersistence call. Write volume scales with session size × persistence frequency.

3. Secondary stack = CoreML on-device AOT force-respecialization — 44/201 samples
MLE5ProgramLibrary _programLibraryHandleWithForceRespecialization:error:
 └ createProgramLibraryHandleWithRespecialization:error:
   └ e5rt_e5_compiler_compile_from_ir_program
     └ MILCompilerForANE / MILCompilerForBnns
       └ bnns::GraphCompile
         └ MIL::Blob::FileWriter::AppendData → fwrite → write

CoreML is force-respecializing an already-compiled model, serializing the full MIL program as text and dumping fp16 weights into ~/Library/Caches/com.FluidApp.app/com.apple.e5rt.e5bundlecache/. App log confirms the cost — each first load of a distinct model takes ~15.5 s.

4. Model-switch thrash in a 16-second window (PID 1015)
19:15:05.412  ASR INIT START -> prepare Parakeet TDT v3
19:15:20.909  "prepared successfully in 15.50s"        <- COLD AOT compile #1
19:17:09.381  MeetingProcessingPipeline: final processing selected backend=local-parakeet-tdt-v2-nemotron-3-v1
19:17:09.501  PrivateAIProvider unloaded cached runtime model  reason=meeting processing
19:17:10.626  prepare Parakeet TDT v2 (English Only)
19:17:26.136  "Models ready"                            <- COLD AOT compile #2
19:17:26.272  ASR INIT START again -> prepare Parakeet TDT v3
19:17:26.499  "Models ready"                            <- warm reload (0.23 s)

The pipeline unloads the resident streaming model, cold-compiles a second ASR model for final processing, then reloads the streaming model — all while persistence is writing.

5. Memory-compressor death spiral
19:03  compressor_size ≈ 745,137 pages   (~11.9 GB)
19:10  memorystatus: suspending FluidVoice [1289] due to swap exhaustion        -> shutdown #1
19:28  compressor_size ≈ 811,686 pages   (~13.0 GB of 24 GB)
19:28  memorystatus: suspending FluidVoice [1015] due to swap exhaustion
19:28  {"compressor_exhausted": 1, ...} killing due to "vm-compressor-space-shortage" (x16 kills)
                                                                                -> shutdown #2
6. Contributing — ANE program retention

12× in 19:00–19:49:

ANE0: ANE_SaveState_block_invoke: WARN:: clientname:FluidVoice is keeping programs loaded and not
freeing - isPowered: 1 Programs Open:1 Wired-memory: 30834688 B

≈29.4 MB wired each, never released on model switch.

7. Contributing — MeetingAutoDetector busy-loop

confirm-rejected reason=busy bundle=com.microsoft.teams2 fires every ~2 s for hours (1,152 occurrences in the 19:xx window alone). This kept the app in a hot state and burned the sustained 60%+ CPU. Also: 19:01:29 [MeetingLive] Live captions dropped audio and resynced.

Root cause chain

Teams meeting detected
 -> MeetingSessionCoordinator starts persisting session
     -> MeetingSessionStore.atomicPrivateWrite rewrites the whole session blob on every enqueue
 -> MeetingProcessingPipeline switches final-processing backend to v2-nemotron
     -> unloads resident v3
     -> cold AOT-compiles v2   (CoreML force-respecialization -> MIL text + fp16 weight dump)
     -> reloads v3
 -> each cycle dirties GBs of file-backed memory
 -> 2.1 GB dirtied in 237 s  -> exceeds the macOS disk-write rate limit
 -> ANE programs retained; compressor grows to ~13 GB
 -> swap exhausted -> kernel SUSPENDS FluidVoice           (attempt #1)
 -> relaunch -> same cycle, faster
 -> swap exhausted -> vm-compressor-space-shortage kills   (attempt #2)

Suggested fixes

P0

  1. Make session persistence incremental (append-only journal or SQLite/WAL); debounce/coalesce saves; never rewrite the whole blob per enqueue; never store raw audio in the persisted JSON.
  2. Eliminate CoreML forceRespecialization — pin MLModelConfiguration (computeUnits/variant) so the compiled e5rt bundle is reused; ship precompiled .mlmodelc where possible.
  3. Stop loading a second ASR model for final processing while streaming. Reuse one model end-to-end, or run final processing in a separate, memory-capped helper after releasing the streaming model.
  4. Fix the MeetingAutoDetector busy-loop (reason=busy should back off / clear).
  5. Release ANE programs explicitly on model switch.

P1
6. Add an in-app memory watchdog (task_vm_info footprint + compressor via host_statistics64); if compressor > ~50% RAM, stop recording, flush, release models, and warn — GUI apps get no jetsam warning before suspension.
7. Don't run streaming ASR + final ASR + persistence concurrently on one async executor (the diag shows all three stacked under a single completeTaskWithClosure).

Note on raw .diag files

The four Apple reports live in /Library/Logs/DiagnosticReports/ (660 root:_analyticsusers) and need admin access to copy. Key excerpts are in the gist; happy to attach the raw files if you tell me the best way.


Reported by an external user; app is not mine. Happy to run any additional diagnostics you need.

Dominant language
Swift
Stars
11.9k
Forks
863
Avg merge
1d 13h
Merged PRs (30d)
28

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from altic-dev/FluidVoice

All issues in altic-dev/FluidVoice

Similar issues

More Swift issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.