{"record":{"id":"603bba573aaa0388","repo":"laurent22/joplin","slug":"invalid-file-name-could-not-extract-filename-from-uri-string","errorCode":null,"errorMessage":"Invalid file name: Could not extract filename from uri string provided","messagePattern":"Invalid file name: Could not extract filename from uri string provided","errorType":"exception","errorClass":"IOExceptionFast","httpStatus":null,"severity":"error","filePath":"packages/react-native-saf-x/android/src/main/java/com/reactnativesafx/utils/EfficientDocumentHelper.java","lineNumber":430,"sourceCode":"        throw new IOExceptionFast(\"could not create file at: \" + unknownStr);\n      }\n      return uri;\n    }\n\n    Uri parentDirOfFile = getDocumentUri(unknownStr, true, false);\n\n    String fileName = UriHelper.getFileName(unknownStr);\n    return createFileInDirectory(parentDirOfFile, fileName, mimeType, replaceIfDestinationExists);\n  }\n\n  private Uri createFileInDirectory(\n    final Uri parentDirOfFile,\n    final String fileName,\n    final String mimeType,\n    final boolean replaceIfDestinationExists\n  ) throws IOException {\n    if (fileName.indexOf(':') != -1) {\n      throw new IOExceptionFast(\n        \"Invalid file name: Could not extract filename from uri string provided\");\n    }\n\n    String creationMimeType = \"*/*\";\n\n    // Some providers append the extension associated with the MIME type. Pass\n    // the MIME type only when the requested name already has an extension;\n    // extensionless Joplin resource IDs must remain extensionless.\n    String correctFileName = fileName;\n\n    if (mimeType != null && !mimeType.equals(\"\")) {\n      int indexOfDot = fileName.lastIndexOf('.');\n      // len - 1 because there should be an extension that has at least 1 letter\n      if (indexOfDot > 0 && indexOfDot < fileName.length() - 1) {\n        correctFileName = fileName.substring(0, indexOfDot);\n        creationMimeType = mimeType;\n      }\n    }","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/laurent22/joplin/blob/981a03c5c9e88130bccff4db47c411d35ec7ae2c/packages/react-native-saf-x/android/src/main/java/com/reactnativesafx/utils/EfficientDocumentHelper.java#L412-L448","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Strip or reject ':' characters from fileName before calling createFile, e.g. fileName.replace(/:/g, '_')","Pass only the base file name (e.g. 'report.pdf'), never a path or URI string, as fileName","If deriving the name from a URI, decode and take the last segment after ':' (DocumentsContract convention) instead of embedding separators","On Windows paths, use path.basename() or equivalent to get the bare file name first"],"exampleFix":"// before\nawait Safx.createFile(treeUri, 'C:\\\\Users\\\\me\\\\report.pdf', 'application/pdf');\n// after\nconst safeName = 'C:\\\\Users\\\\me\\\\report.pdf'.split(/[\\\\/:]/).pop() ?? 'report.pdf';\nawait Safx.createFile(treeUri, safeName, 'application/pdf');","handlingStrategy":"validation","validationCode":"function assertSafeSafFileName(name: string) {\n\tif (!name || name.includes(':')) {\n\t\tthrow new Error(`Invalid SAF file name: ${JSON.stringify(name)}`);\n\t}\n}\n// call before: assertSafeSafFileName(fileName); await Safx.createFile(...)","typeGuard":"const isSafeFileName = (name: unknown): name is string =>\n\ttypeof name === 'string' && name.length > 0 && !name.includes(':') && !name.includes('/');","tryCatchPattern":null,"preventionTips":["Never pass full paths or URIs as fileName; always pass the bare display name","Sanitize user-supplied names by replacing [\\\\/:*?\"<>|] before any SAF call","When deriving a name from a URI, use the last segment after ':' (DocumentsContract convention), not the raw string"],"tags":["android","saf","filename","validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"981a03c5c9e88130bccff4db47c411d35ec7ae2c","analyzedAt":"2026-09-17T14:49:40.960Z","contentChangedAt":"2026-09-17T14:49:40.960Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}