laurent22/joplin · error · IOExceptionFast

a file or directory already exist at

Error message

a file or directory already exist at: ${uri}

What it means

EfficientDocumentHelper.createFile (react-native-saf-x) throws "a file or directory already exist at: <uri>" when the target SAF/document URI already resolves and the caller did not pass replaceIfDestinationExists. The helper first checks whether a document already exists at the target and refuses to overwrite it unless replacement is requested.

Solutions

  1. Pass replaceIfDestinationExists: true in the createFile options to overwrite.
  2. Generate a unique target filename (e.g. append timestamp) before creating.
  3. Delete or move the existing document first, then create the file.

Example fix

// before
await SafX.createFile(treeUri, 'notes.json', 'text/json');
// after
await SafX.createFile(treeUri, 'notes.json', 'text/json', { replaceIfDestinationExists: true });
Defensive patterns

Strategy: try-catch

Try / catch

try { await SafX.createFile(treeUri, name, mime); } catch (e) { if (String(e.message).includes('already exist')) await SafX.createFile(treeUri, name, mime, { replaceIfDestinationExists: true }); }

Prevention

When it happens

Trigger: Calling createFile (via the JS module's createFile) with a target URI that already exists while replaceIfDestinationExists is false.

Common situations: Writing a file to a folder where a same-named file exists; retrying an export after a previous partial success; users re-running a save-to-SD operation without unique filenames.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of laurent22/joplin@981a03c5c9 (2026-09-17). Data as JSON: /api/errors/77e48a48106366a4. Report an issue: GitHub.

Appendix: source

Thrown at packages/react-native-saf-x/android/src/main/java/com/reactnativesafx/utils/EfficientDocumentHelper.java:401

    if (!renameResult.equals(newName)) {
      throw new RenameFailedException(uri, newName, newUri, renameResult);
    }
    return newUri;
  }

  private Uri createFile(
    final String unknownStr, final String mimeType, final boolean replaceIfDestinationExists
  ) throws IOException {
    Uri uri = null;

    try {
      uri = getDocumentUri(unknownStr, false, true);
    } catch (FileNotFoundException ignored) {
    }

    if (uri != null) {
      if (replaceIfDestinationExists) return uri;
      throw new IOExceptionFast("a file or directory already exist at: " + uri);
    }

    uri = UriHelper.getUnifiedUri(unknownStr);

    if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {
      File file = new File(uri.getPath());
      file.getParentFile().mkdirs();
      boolean created = file.createNewFile();
      if (!created) {
        if (replaceIfDestinationExists && file.exists() && file.isFile()) return uri;
        throw new IOExceptionFast("could not create file at: " + unknownStr);
      }
      return uri;
    }

    Uri parentDirOfFile = getDocumentUri(unknownStr, true, false);

    String fileName = UriHelper.getFileName(unknownStr);

View on GitHub (pinned to 981a03c5c9)