stride3d/stride · error · Exception

Failed to create Celt encoder.

Error message

Failed to create Celt encoder.

What it means

Thrown from the Celt constructor when opus_custom_encoder_create returns NULL, i.e. the native codec could not create an encoder for the given mode and channels. Only thrown when decoderOnly is false, i.e. the caller requested encoding capability.

Solutions

  1. If only playback is needed, construct Celt with decoderOnly:true to skip encoder creation.
  2. Verify the channel count is supported by the Celt encoder (typically 1 or 2).
  3. Ensure the correct native celt/opus library version is bundled for the target platform.
  4. Reduce concurrent codec instances or free memory if native allocation fails.

Example fix

// before
var celt = new Celt(48000, 256, channels, decoderOnly:false);
// after
var celt = new Celt(48000, 256, Math.Min(channels, 2), decoderOnly:false); // or true if playback-only
Defensive patterns

Strategy: try-catch

Validate before calling

public static bool IsSupportedChannelCount(int channels) => channels is 1 or 2;
public static bool EncoderNeeded(bool playbackOnly) => !playbackOnly;

Try / catch

try
{
    var celt = new Celt(48000, bufferSize, channels, decoderOnly: false);
}
catch (Exception ex) when (ex.Message.Contains("Failed to create Celt encoder"))
{
    logger.Error("Celt encoder creation failed; disabling microphone capture.");
    celt = new Celt(48000, bufferSize, channels, decoderOnly: true);
}

Prevention

When it happens

Trigger: Constructing Celt with decoderOnly:false and an unsupported channel count, or native encoder allocation failing (memory, incompatible native lib) on the AVFoundation path.

Common situations: Requesting an encoder on devices with tight memory; mismatched native opus/celt binaries; passing channel counts outside codec limits during microphone capture setup.

Related errors


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

Appendix: source

Thrown at sources/engine/Stride.Audio/Native/Celt.AVFoundation.cs:57

        public Celt(int sampleRate, int bufferSize, int channels, bool decoderOnly)
        {
            SampleRate = sampleRate;
            BufferSize = bufferSize;
            Channels = channels;

            mode = opus_custom_mode_create(sampleRate, bufferSize, IntPtr.Zero);
            if (mode == IntPtr.Zero)
                throw new Exception("Failed to create Celt custom mode.");

            decoder = opus_custom_decoder_create(mode, channels, IntPtr.Zero);
            if (decoder == IntPtr.Zero)
                throw new Exception("Failed to create Celt decoder.");

            if (!decoderOnly)
            {
                encoder = opus_custom_encoder_create(mode, channels, IntPtr.Zero);
                if (encoder == IntPtr.Zero)
                    throw new Exception("Failed to create Celt encoder.");
            }
        }

        public void Dispose()
        {
            if (encoder != IntPtr.Zero) { opus_custom_encoder_destroy(encoder); encoder = IntPtr.Zero; }
            if (decoder != IntPtr.Zero) { opus_custom_decoder_destroy(decoder); decoder = IntPtr.Zero; }
            if (mode != IntPtr.Zero) { opus_custom_mode_destroy(mode); mode = IntPtr.Zero; }
        }

        public unsafe int Decode(byte[] inputBuffer, int inputBufferSize, short[] outputSamples)
        {
            Debug.Assert((uint)inputBufferSize <= (uint)inputBuffer.Length);
            fixed (short* samplesPtr = outputSamples)
            fixed (byte* bufferPtr = inputBuffer)
            {
                return opus_custom_decode(decoder, bufferPtr, inputBufferSize, samplesPtr, outputSamples.Length / Channels);
            }

View on GitHub (pinned to 96fad776d2)