Render fails with 'Operation Stopped' when source files are Google Drive File Stream symlinks
Problem
sequence-render-final fails with "Operation Stopped" when source media files are accessed through Google Drive File Stream symlinks. The AVFoundation composition builds successfully (all assets load, correct duration reported), but AVAssetExportSession.exportAsynchronously fails immediately or hangs.
User impact: Render produces no output or a partial/hung file. The user must manually copy source footage to local storage before rendering. Premiere .prproj export is unaffected (it references paths, doesn't decode media).
Session reference: ba0e2a61 — yulian@stonecuttercreative.com (SXSW multi-cam reel, Mar 14 batch)
Symptoms
- Composition builds successfully —
CompositionBuilder.buildComposition()reports correct duration, all tracks load AVAssetExportSessionexport fails with "Operation Stopped" (AVError.exportFailed)ffprobereads the same files without issue- Agent workaround: extract segments locally via
ffmpeg -ss -t -c copy, rebuild sequence pointing to local segments — render succeeds - Even with local segments, V2 overlay + cross-dissolve transitions caused the export to hang (49MB partial file, no progress). V1-only hard cuts rendered successfully.
Root Cause
No symlink resolution in the asset loading path. CompositionBuilder.loadAsset() at calav/Sources/Core/CompositionBuilder.swift:849-862 creates AVAsset(url:) with the symlink URL directly. No call to URL.resolvingSymlinksInPath(), no realpath(), no cloud-file detection.
Google Drive File Stream presents files as symlinks under ~/Library/CloudStorage/GoogleDrive-*/. These point to a virtual FUSE filesystem that serves content on-demand from the cloud. The key asymmetry:
- Composition build succeeds because
AVAsset(url:)+asset.tracks(withMediaType:)only reads container headers (small sequential read at file start) - Export fails because
AVAssetExportSessionmust decode compressed frame data across the full clip duration, requiring random-access I/O into cloud-backed files. AVFoundation's internal export I/O strategy has different timeout/error-recovery behavior than standard file reads. - V2 overlay compounds the issue because cross-dissolve transitions require simultaneous decoding from two source tracks, doubling concurrent cloud I/O
Relevant Code
CompositionBuilder.swift:849-870 — loadAsset() and resolveFilePath()
→ AVAsset(url: fileURL) — no symlink resolution, no AVURLAsset options
→ FileManager.fileExists(atPath:) — follows symlinks, returns true
ExportSession.swift:119-197 — startExport()
→ AVAssetExportSession(asset:presetName:) — HighestQuality preset
→ session.exportAsynchronously — fails with "Operation Stopped"
→ session.error?.localizedDescription — only error info captured
export.rs:136-226 — Rust FFI wrapper
→ CString paths passed through, no symlink resolution on Rust side either
Proposed Fix
Detection + local caching approach:
- In
CompositionBuilder.resolveFilePath(), resolve the final URL through symlinks:fileURL.resolvingSymlinksInPath() - Detect if the resolved path is under a cloud storage provider mount (Google Drive, iCloud, Dropbox) by checking path prefix against known cloud storage locations (
~/Library/CloudStorage/) - If cloud-backed, either:
- Option A: Pre-extract the needed segment locally via ffmpeg stream copy before building the composition (similar to what the agent did manually). This is the most reliable approach.
- Option B: Log a warning and attempt the render anyway, with a clearer error message on failure ("Source files are on Google Drive — copy to local storage or use Premiere export instead").
Minimum viable fix: Add URL.resolvingSymlinksInPath() to resolveFilePath() and add cloud-path detection with a user-facing warning. This alone may not fix the render (the underlying issue is AVFoundation's I/O behavior with FUSE filesystems), but it would give a clear error message instead of "Operation Stopped."
Additional: Capture session.error.underlyingErrors in ExportSession.swift for better diagnostics on export failures.
Affected Users
Any user with source footage on Google Drive File Stream, iCloud Drive, or potentially Dropbox. Google Drive is common in professional video production teams sharing footage.
Labels
bug, render, avfoundation
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗