stride3d/stride · error · AssetException

Failed to compile a sound asset, ffmpeg was not found.

Error message

Failed to compile a sound asset, ffmpeg was not found.

What it means

SoundAssetCompiler requires the external ffmpeg tool to convert audio sources before Celt encoding. ToolLocator.LocateTool("ffmpeg") returned null (ffmpeg not on PATH, not bundled, or not executable), so compilation aborts with an AssetException before any conversion is attempted.

Solutions

  1. Install ffmpeg and ensure it is on the system PATH (or set the tool location Stride uses)
  2. On Linux/macOS run chmod +x on the ffmpeg binary if it exists but isn't executable
  3. Verify with 'ffmpeg -version' in a shell from the same environment the build runs in
  4. On CI, add an ffmpeg install step to the pipeline before the build
Defensive patterns

Strategy: validation

Validate before calling

// before building sound assets, verify ffmpeg is locatable
if (ToolLocator.LocateTool("ffmpeg", ensureExecutable: true) is null)
    throw new InvalidOperationException("Install ffmpeg and add it to PATH before building audio assets.");

Type guard

static bool FfmpegAvailable() => ToolLocator.LocateTool("ffmpeg", ensureExecutable: true) != null;

Try / catch

try
{
    await CompileSoundAsync(asset);
}
catch (AssetException ex) when (ex.Message.Contains("ffmpeg was not found"))
{
    logger.Error("Install ffmpeg (https://ffmpeg.org) and ensure it is on PATH, then rebuild.");
}

Prevention

When it happens

Trigger: DoCommandOverride runs on a sound asset and ToolLocator cannot locate an ffmpeg executable (returns null).

Common situations: ffmpeg not installed on the build machine/CI agent, ffmpeg present but not on PATH, downloaded ffmpeg lacking execute permission (Linux/macOS), a stripped-down Stride install without bundled tools.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/2fb93cb16d7d4330. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Assets/Media/SoundAssetCompiler.cs:44

        {
            var asset = (SoundAsset)assetItem.Asset;
            result.BuildSteps = new AssetBuildStep(assetItem);
            result.BuildSteps.Add(new DecodeSoundFileCommand(targetUrlInStorage, asset, assetItem.Package));
        }

        protected class DecodeSoundFileCommand : AssetCommand<SoundAsset>
        {
            public DecodeSoundFileCommand(string url, SoundAsset parameters, IAssetFinder assetFinder)
                : base(url, parameters, assetFinder)
            {
                Version = 5;
            }

            /// <inheritdoc />
            protected override async Task<ResultStatus> DoCommandOverride(ICommandContext commandContext)
            {
                // Get path to ffmpeg
                var ffmpeg = ToolLocator.LocateTool("ffmpeg", ensureExecutable: true)?.ToOSPath() ?? throw new AssetException("Failed to compile a sound asset, ffmpeg was not found.");

                // Get absolute path of asset source on disk
                var assetDirectory = Parameters.Source.GetParent();
                var assetSource = UPath.Combine(assetDirectory, Parameters.Source);

                // Execute ffmpeg to convert source to PCM and then encode with Celt
                var tempFile = Path.GetTempFileName();
                try
                {
                    var channels = Parameters.Spatialized ? 1 : 2;
                    var commandLine = "  -hide_banner -loglevel error" + // hide most log output
                                      $" -i \"{assetSource.ToOSPath()}\"" + // input file
                                      $" -f f32le -acodec pcm_f32le -ac {channels} -ar {Parameters.SampleRate}" + // codec
                                      $" -map 0:{Parameters.Index}" + // stream index
                                      $" -y \"{tempFile}\""; // output file (always overwrite)
                    var ret = await ShellHelper.RunProcessAndGetOutputAsync(ffmpeg, commandLine, commandContext.Logger);
                    if (ret != 0 || commandContext.Logger.HasErrors)
                    {

View on GitHub (pinned to 96fad776d2)