stride3d/stride · error · Exception

Unable to read

Error message

Unable to read: {0} 

What it means

MediaCodec (Android) backend of StreamedBufferSoundSource throws this in InitializeMediaExtractor when the given mediaDataUrl points to a Java.IO.File that reports CanRead() == false. The library refuses to open a media source it cannot read at the filesystem level. It guards the MediaExtractor.SetDataSource call with an early, descriptive check.

Solutions

  1. Verify the file exists and is readable: new Java.IO.File(path).Exists() && CanRead() before calling
  2. Request runtime READ_EXTERNAL_STORAGE / MANAGE_EXTERNAL_STORAGE permissions on Android, or use app-internal storage for media files
  3. For bundled assets, copy the asset to app cache/files first, or use a data source that supports content:// streams
  4. Check the path for typos and confirm InputFile.AbsolutePath points to the actual media file, not a directory

Example fix

// before
var source = new StreamedBufferSoundSource("/storage/emulated/0/Music/track.ogg", services);
// after
var file = new Java.IO.File(path);
if (!file.Exists() || !file.CanRead())
    throw new FileNotFoundException($"Media file not readable: {path}");
var source = new StreamedBufferSoundSource(path, services);
Defensive patterns

Strategy: validation

Validate before calling

var f = new Java.IO.File(path);
if (f == null || !f.Exists() || f.IsDirectory || !f.CanRead())
    throw new FileNotFoundException($"Media file not readable: {path}");

Try / catch

try
{
    source = new StreamedBufferSoundSource(path, services);
}
catch (Exception ex) when (ex.Message.StartsWith("Unable to read:"))
{
    Logger.Error($"Cannot read media at {path}: {ex.Message}");
    source = null;
}

Prevention

When it happens

Trigger: Passing a path to InitializeMediaExtractor that does not exist, lacks read permission, is a directory, or lies in app-private storage inaccessible to the current context (e.g. raw absolute path to shared storage on modern Android without permissions).

Common situations: Hard-coded absolute paths like /storage/emulated/0/... on Android 10+ scoped storage; missing READ_EXTERNAL_STORAGE permission; typo in the media file path; asset bundled in the APK referenced as a file path instead of streamed via AssetFileDescriptor.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

Thrown at sources/engine/Stride.Audio/StreamedBufferSoundSource.MediaCodec.cs:33

        private MediaCodec audioMediaDecoder = null;
        private int trackIndexAudio = -1;

        private Java.IO.File InputFile;
        private Java.IO.FileInputStream InputFileStream;

        private bool extractionOutputDone = false;
        private bool extractionInputDone = false;

        partial void InitializeMediaExtractor(string mediaDataUrl, long startPosition, long length)
        {
            if (mediaDataUrl == null)
                throw new ArgumentNullException(nameof(mediaDataUrl));

            ReleaseMediaInternal();

            InputFile = new Java.IO.File(mediaDataUrl);
            if (!InputFile.CanRead())
                throw new Exception(string.Format("Unable to read: {0} ", InputFile.AbsolutePath));

            InputFileStream = new Java.IO.FileInputStream(InputFile.AbsolutePath);

            audioMediaExtractor = new MediaExtractor();
            audioMediaExtractor.SetDataSource(InputFileStream.FD, startPosition, length);
            trackIndexAudio = FindAudioTrack(audioMediaExtractor);
            if (trackIndexAudio < 0)
            {
                ReleaseMediaInternal();
                Logger.Error($"The input file '{mediaDataUrl}' does not contain any audio track.");
                return;
            }

            audioMediaExtractor.SelectTrack(trackIndexAudio);
            var audioFormat = audioMediaExtractor.GetTrackFormat(trackIndexAudio);

            var mime = audioFormat.GetString(MediaFormat.KeyMime);
            audioMediaDecoder = MediaCodec.CreateDecoderByType(mime);

View on GitHub (pinned to 96fad776d2)