Skip to content

🐛 Bug Report: Storage uploads fail on Expo SDK 55 because the SDK imports a removed FileSystem API #112

Open

Description

@isaachinman

👟 Reproduction steps

  1. Create an Expo SDK 55 application with these dependencies:
{
  "expo": "55.0.3",
  "expo-file-system": "55.0.9",
  "react-native": "0.83.2",
  "react-native-appwrite": "0.34.0"
}
  1. Upload a local file using Storage.createFile().

react-native-appwrite imports:

import * as FileSystem from 'expo-file-system'

Its upload implementation then calls:

FileSystem.readAsStringAsync(...)

A minimal runtime reproduction is:

import * as FileSystem from 'expo-file-system'

await FileSystem.readAsStringAsync('file:///path/to/file')

👍 Expected behavior

react-native-appwrite should support the current Expo FileSystem version permitted by its expo: "*" peer dependency, and Storage.createFile() should read and upload the selected file.

The SDK should not require an obsolete second version of an Expo native module.

👎 Actual Behavior

Expo FileSystem 55 keeps readAsStringAsync only under expo-file-system/legacy. Importing it from the top-level module produces this runtime error:

Method readAsStringAsync imported from "expo-file-system" is deprecated.
You can migrate to the new filesystem API using "File" and "Directory"
classes or import the legacy API from "expo-file-system/legacy".

Consequently, native Appwrite Storage uploads cannot read the file.

react-native-appwrite@0.34.0 still declares:

{
  "expo-file-system": "18.*.*"
}

Changing the SDK import to the following fixes the existing upload implementation on Expo SDK 55:

import * as FileSystem from 'expo-file-system/legacy'

Longer-term, the upload implementation could migrate to Expo’s current File API. The package should also declare a supported Expo/FileSystem compatibility range rather than depending directly on version 18 while accepting every Expo version.

Related issues cover the original FileSystem integration and earlier Expo upgrades, but not this SDK 55 API incompatibility:

🎲 Appwrite version

Different version — Appwrite Cloud. The error occurs locally before the upload request reaches Appwrite.

💻 Operating system

MacOS development host; Expo native application targeting iOS.

🧱 Your Environment

  • Expo SDK: 55.0.3

  • Expo FileSystem: 55.0.9

  • React Native: 0.83.2

  • React: 19.2.0

  • React Native Appwrite SDK: 0.34.0

  • Bun: 1.3.1

  • Expo SDK 55 New Architecture

  • I checked and didn't find a similar issue.

  • I have read the Code of Conduct.

Activity

  1. yazanTah commented on Jul 22, 2026

    @yazanTah

    Confirming this on react-native-appwrite@0.31.0 as well (still present in 0.34.0, verified by inspecting the published tarball). Hits Storage.createFile() specifically for files over the 5MB chunk threshold — small files go through the single-request path and never touch FileSystem.readAsStringAsync, so it only surfaces once someone uploads a larger PDF/audio file, which made it a bit tricky to track down.

    Workaround we applied via patch-package: swap both the require and import of expo-file-system in dist/cjs/sdk.js and dist/esm/sdk.js for the /legacy subpath, matching the fix already suggested above. Confirms the same root cause and fix.

  2. isaachinman commented on Jul 23, 2026

    @isaachinman
    Author

    @ChiragAgg5k @ArnabChatterjee20k Who is the official maintainer? Can we get a quick response on this one? Quite an easy fix.

  3. devstojko commented on Aug 2, 2026

    @devstojko
    Unsupported FormDataPart implementation
    

    Root cause: Expo's global fetch is now its WinterCG-compliant implementation, whose FormData serializer only accepts strings and Blobs — it rejects the React Native-style { uri, name, type } file parts this SDK appends. So on current Expo both upload paths are broken: < 5 MB by the fetch FormData rejection, > 5 MB by the removed legacy FileSystem import described in this issue.

    Workaround (no patch-package needed; verified on Expo SDK 57 + react-native-appwrite@0.34.0): pass an expo-file-system File instead of a plain object — it implements Blob, which the new fetch accepts, while still exposing the uri/size/name/type fields the SDK reads internally:

    import { File } from 'expo-file-system';
    
    const file = new File(asset.uri); // e.g. an expo-image-picker asset
    
    await storage.createFile({
      bucketId,
      fileId: ID.unique(),
      file: file as unknown as { uri: string; name: string; type: string; size: number },
      permissions: [/* ... */],
    });

    Caveat: keep files under the 5 MB chunk threshold — the chunked path still hits the legacy readAsStringAsync problem from this issue (fix pending in appwrite/sdk-generator#1691). Longer term, migrating the SDK's upload to Blob parts would fix both failure modes at once and drop the legacy FileSystem dependency entirely.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions