SubtitleEdit/subtitleedit · error · InvalidOperationException
MPV delegates not loaded for software rendering.
Error message
MPV delegates not loaded for software rendering.
What it means
InvalidOperationException: after LoadLibraryInternal, at least one critical P/Invoke delegate (_mpvInitialize, _mpvRenderContextCreate, or _mpvRenderContextSetUpdateCallback) is still null. The native library loaded, but the expected symbols were not found, indicating an ABI/version mismatch.
Source
Thrown at src/ui/Logic/VideoPlayers/LibMpvDynamic/LibMpvDynamicPlayer.cs:1779
var err = DoMpvCommand("set", "aid", trackId.ToString(CultureInfo.InvariantCulture));
if (err < 0)
{
Se.LogError(new InvalidOperationException(GetErrorString(err)), "LibMpvDynamicPlayer SetAudioTrack");
}
}
public void InitializeWithSoftwareRendering()
{
LoadLibraryInternal();
EnsureNotDisposed();
// Set mpv to use software rendering
SetOptionString("vo", "libmpv");
SetStartPausedOption();
if (_mpvInitialize == null || _mpvRenderContextCreate == null || _mpvRenderContextSetUpdateCallback == null)
{
throw new InvalidOperationException("MPV delegates not loaded for software rendering.");
}
SetYtDlpPathOption();
// Initialize mpv
var err = _mpvInitialize(_mpv);
if (err < 0)
{
throw new InvalidOperationException(GetErrorString(err));
}
_coreInitialized = true;
// Build render context params for software rendering
var apiTypeBytes = Encoding.UTF8.GetBytes(MPV_RENDER_API_TYPE_SW + "\0");
var apiTypePtr = Marshal.AllocHGlobal(apiTypeBytes.Length);
Marshal.Copy(apiTypeBytes, 0, apiTypePtr, apiTypeBytes.Length);
View on GitHub (pinned to 17a9f07487)
Solutions
- Install a libmpv build recent enough to export mpv_render_context_create and mpv_render_context_set_update_callback.
- Ensure the loader resolves the bundled libmpv rather than a stale system copy (check rpath / LD_LIBRARY_PATH / dyld).
- Fall back to a GPU vo context if software rendering is unavailable on this build.
Example fix
// before
if (_mpvInitialize == null || _mpvRenderContextCreate == null || _mpvRenderContextSetUpdateCallback == null)
throw new InvalidOperationException("MPV delegates not loaded for software rendering.");
// after
if (_mpvInitialize == null || _mpvRenderContextCreate == null || _mpvRenderContextSetUpdateCallback == null)
{
logger.LogWarning("libmpv lacks software-render API; falling back to GPU vo");
SwitchToGpuVo();
return;
} Defensive patterns
Strategy: validation
Validate before calling
if (!LibMpvExportsSymbol("mpv_render_context_create"))
{
logger.LogWarning("libmpv lacks render API; using GPU vo");
SwitchToGpuVo();
return;
} Try / catch
try { player.InitializeWithSoftwareRendering(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("delegates not loaded"))
{
logger.LogWarning("{Msg}; falling back to GPU vo", ex.Message);
SwitchToGpuVo();
} Prevention
- Bundle a libmpv build that exports mpv_render_context_*.
- Ensure the loader resolves the bundled library, not a stale system copy.
- Version-gate the software-rendering feature.
- Provide a GPU-vo fallback.
When it happens
Trigger: A libmpv is present but too old to export mpv_render_context_create/set_update_callback, the wrong library revision was loaded (e.g. libmpv.so.1 vs libmpv.so.2), a stripped/minimal build lacking the render API, or symbols renamed across versions.
Common situations: A distro libmpv older than required, multiple libmpv versions on the library path, or a custom minimal build compiled without the render context API.
Related errors
- Failed to create software render context: {GetErrorString(er
- Failed to initialize mpv: {_mpvContext.GetErrorString(err)}
- Failed to initialize mpv: {_mpvContext.GetErrorString(err)}
- Failed to initialize mpv: {player.GetErrorString(err)}
- Failed to initialize mpv: {_mpvPlayer.GetErrorString(err)}
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/d1dfe11836f46b84.
Report an issue: GitHub.