stride3d/stride · error · Exception
Unable to read
Error message
Unable to read: {0} What it means
MediaCodecExtractorBase.Initialize opens the media file on Android via Java.IO.File. If the file exists but is not readable (or does not exist), it throws a generic Exception 'Unable to read: <path>' before any extractor is created.
Solutions
- Check File.Exists and CanRead on the path before calling Initialize and surface a clear error.
- Copy bundled/streamed assets to the app's writable internal storage (FilesDir/CacheDir) and pass that path.
- Request and grant Android storage runtime permissions (or use app-scoped storage / SAF).
- Verify the path string (case, extension, absolute vs relative) matches the on-device file.
Example fix
// before
extractor.Initialize("/sdcard/DCIM/movie.mp4", MediaType.Video);
// after
var path = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "movie.mp4");
CopyAssetTo("movie.mp4", path); // copy from assets to app storage
if (System.IO.File.Exists(path))
extractor.Initialize(path, MediaType.Video); Defensive patterns
Strategy: validation
Validate before calling
var f = new Java.IO.File(url);
if (!f.Exists() || !f.CanRead())
throw new IOException($"Media file missing or unreadable: {url}");
extractor.Initialize(url, mediaType); Try / catch
try { extractor.Initialize(url, mediaType); }
catch (Exception ex) when (ex.Message.StartsWith("Unable to read:")) { /* fall back to app-storage copy of the asset */ } Prevention
- Copy bundled assets to internal storage before playback
- Request Android storage permissions at runtime
- Validate paths (exists + can-read) before Initialize
- Use app-scoped storage rather than shared external storage
When it happens
Trigger: Passing a URL/path to a file with no read permission, a non-existent path, an Android storage location not accessible to the app (e.g. external storage without permission), or a content:// URI that cannot be mapped to a File.
Common situations: Missing READ_EXTERNAL_STORAGE / storage runtime permission; streaming assets not copied to a readable location; path case-sensitivity mismatches on Android; files in app-private dirs of another app.
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
- No track found in
- The Media Codec Extractor has not been initialized
- mediaCodec has already been initialized
- PlayMedia failed: MediaCodecScheduler is null
- PauseMedia failed: MediaCodecScheduler is null
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/8b8aad05f95d000a.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Video/Android/MediaCodecExtractorBase.cs:106
protected MediaCodecExtractorBase(VideoInstance videoInstance, MediaSynchronizer scheduler, Surface decoderOutputSurface = null)
{
Scheduler = scheduler;
VideoInstance = videoInstance;
this.decoderOutputSurface = decoderOutputSurface;
currentState = SchedulerAsyncCommandEnum.Stop;
}
public void Initialize(IServiceRegistry services, string url, long startPosition, long length)
{
if (isInitialized)
return;
try
{
inputFile = new Java.IO.File(url);
if (!inputFile.CanRead())
throw new Exception(string.Format("Unable to read: {0} ", inputFile.AbsolutePath));
inputFileDescriptor = new Java.IO.FileInputStream(inputFile);
// ===================================================================================================
// Initialize the audio media extractor
mediaExtractor = new MediaExtractor();
mediaExtractor.SetDataSource(inputFileDescriptor.FD, startPosition, length);
var videoTrackIndex = FindTrack(mediaExtractor, MediaType.Video);
var audioTrackIndex = FindTrack(mediaExtractor, MediaType.Audio);
HasAudioTrack = audioTrackIndex >= 0;
mediaTrackIndex = MediaType == MediaType.Audio ? audioTrackIndex : videoTrackIndex;
if (mediaTrackIndex < 0)
throw new Exception(string.Format($"No {MediaType} track found in: {inputFile.AbsolutePath}"));
mediaExtractor.SelectTrack(mediaTrackIndex);
View on GitHub (pinned to 96fad776d2)