laurent22/joplin · error · IOExceptionFast

Invalid file name: Could not extract filename from uri…

Error message

Invalid file name: Could not extract filename from uri string provided

What it means

react-native-saf-x throws this when createFileInDirectory is asked to create a file whose name contains a colon (':'). SAF document display names must not contain ':' characters, so the library rejects the name up front rather than producing a document the provider will mishandle. It is defensive input validation on the fileName argument.

Solutions

  1. Strip or reject ':' characters from fileName before calling createFile, e.g. fileName.replace(/:/g, '_')
  2. Pass only the base file name (e.g. 'report.pdf'), never a path or URI string, as fileName
  3. If deriving the name from a URI, decode and take the last segment after ':' (DocumentsContract convention) instead of embedding separators
  4. On Windows paths, use path.basename() or equivalent to get the bare file name first

Example fix

// before
await Safx.createFile(treeUri, 'C:\\Users\\me\\report.pdf', 'application/pdf');
// after
const safeName = 'C:\\Users\\me\\report.pdf'.split(/[\\/:]/).pop() ?? 'report.pdf';
await Safx.createFile(treeUri, safeName, 'application/pdf');
Defensive patterns

Strategy: validation

Validate before calling

function assertSafeSafFileName(name: string) {
	if (!name || name.includes(':')) {
		throw new Error(`Invalid SAF file name: ${JSON.stringify(name)}`);
	}
}
// call before: assertSafeSafFileName(fileName); await Safx.createFile(...)

Type guard

const isSafeFileName = (name: unknown): name is string =>
	typeof name === 'string' && name.length > 0 && !name.includes(':') && !name.includes('/');

Prevention

When it happens

Trigger: Calling createFile (or any path reaching createFileInDirectory via fileUri/destinationUri) with a fileName containing ':', e.g. 'C:\\file.txt' (a Windows path passed as a name), 'foo:bar.txt', or a name sliced from a full content:// URI.

Common situations: Passing a full Windows path instead of just the file name; concatenating a scheme prefix into the name; extracting a name from a URI incorrectly so a ':' leaks in; user-supplied names not sanitized on Android where ':' is legal in some filesystems but not SAF.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

        throw new IOExceptionFast("could not create file at: " + unknownStr);
      }
      return uri;
    }

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

    String fileName = UriHelper.getFileName(unknownStr);
    return createFileInDirectory(parentDirOfFile, fileName, mimeType, replaceIfDestinationExists);
  }

  private Uri createFileInDirectory(
    final Uri parentDirOfFile,
    final String fileName,
    final String mimeType,
    final boolean replaceIfDestinationExists
  ) throws IOException {
    if (fileName.indexOf(':') != -1) {
      throw new IOExceptionFast(
        "Invalid file name: Could not extract filename from uri string provided");
    }

    String creationMimeType = "*/*";

    // Some providers append the extension associated with the MIME type. Pass
    // the MIME type only when the requested name already has an extension;
    // extensionless Joplin resource IDs must remain extensionless.
    String correctFileName = fileName;

    if (mimeType != null && !mimeType.equals("")) {
      int indexOfDot = fileName.lastIndexOf('.');
      // len - 1 because there should be an extension that has at least 1 letter
      if (indexOfDot > 0 && indexOfDot < fileName.length() - 1) {
        correctFileName = fileName.substring(0, indexOfDot);
        creationMimeType = mimeType;
      }
    }

View on GitHub (pinned to 981a03c5c9)