AvaloniaUI/Avalonia · error · InvalidOperationException

Failed to open content stream

Error message

Failed to open content stream

What it means

Thrown by AndroidStorageFile.OpenRead when OpenContentStream returns null — i.e. neither the virtual-file path nor ContentResolver.OpenInputStream produced a usable Stream for the content:// URI. The file is bookmarked/referenced but Android cannot open it for reading at this moment.

Source

Thrown at src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs:484

    public WellKnownAndroidStorageFolder(Activity activity, string identifier, AndroidUri uri, bool needsExternalFilesPermission)
        : base(activity, uri, needsExternalFilesPermission)
    {
        Name = identifier;
    }

    public override string Name { get; }
}

internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkFile
{
    public AndroidStorageFile(Activity activity, AndroidUri uri, AndroidStorageFolder? parent = null, AndroidUri? permissionRoot = null) : base(activity, uri, false, parent, permissionRoot)
    {
    }

    public Task<Stream> OpenReadAsync() => Task.FromResult(OpenRead());

    public Stream OpenRead() => OpenContentStream(Activity, Uri, false)
        ?? throw new InvalidOperationException("Failed to open content stream");

    public Task<Stream> OpenWriteAsync() => Task.FromResult(OpenContentStream(Activity, Uri, true)
        ?? throw new InvalidOperationException("Failed to open content stream"));

    private Stream? OpenContentStream(Context context, AndroidUri uri, bool isOutput)
    {
        var isVirtual = IsVirtualFile(context, uri);
        if (isVirtual)
        {
            Logger.TryGet(LogEventLevel.Verbose, LogArea.AndroidPlatform)?.Log(this, "Content URI was virtual: '{Uri}'", uri);
            return GetVirtualFileStream(context, uri, isOutput);
        }

        return isOutput
            ? context.ContentResolver?.OpenOutputStream(uri, "wt")
            : context.ContentResolver?.OpenInputStream(uri);
    }

View on GitHub (pinned to 11c5427268)

Solutions

  1. Verify takePersistableUriPermission was called and the FLAG_GRANT_READ_URI_PERMISSION persisted before using the bookmark.
  2. Catch InvalidOperationException (or the underlying null) and re-prompt the user to re-pick the file when the URI is stale.
  3. For virtual files, ensure the device/provider can produce the requested representation; fall back to a different MIME type.
  4. Check AndroidStorageFile existence via GetItemAsync/DocumentsContract before opening.

Example fix

// before
using var stream = file.OpenRead();

// after
try
{
    using var stream = file.OpenRead();
    // read
}
catch (InvalidOperationException)
{
    // permission revoked or file gone — re-prompt
    await ReRequestFileAccess();
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the URI is still resolvable before opening for read
var info = await DocumentsContract.GetDocumentMetadata(Activity.ContentResolver, file.Uri);
if (info is null) return; // stale or permission lost

Try / catch

try { using var s = file.OpenRead(); /* read */ }
catch (InvalidOperationException) { /* permission revoked or file gone */ await ReRequestFileAccess(); }

Prevention

When it happens

Trigger: Calling OpenRead()/OpenReadAsync() on an AndroidStorageFile whose URI can no longer be opened: the persistent permission was revoked, the underlying document was deleted/moved, the file is virtual and the alternate stream MIME type produced no stream, or ContentResolver is unavailable.

Common situations: Persisted bookmarks across app restarts where the user revoked SAF permission or the file was deleted; accessing content from another app that has since been uninstalled; virtual documents (e.g. Google Drive) whose alternate representation isn't available offline; transient provider errors on certain OEMs.

Related errors


AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13). Data as JSON: /api/errors/4b21d094d74c70e0. Report an issue: GitHub.