laurent22/joplin · error · IOExceptionFast
The created file name was not as expected: input name was
Error message
The created file name was not as expected: input name was '${fileName}' but got: '${createdFileName}' What it means
After SAF creates the document, the provider may adjust the name (append an extension derived from the MIME type, or dedupe a collision by appending ' (1)'). When the created file's display name differs from the requested fileName and replaceIfDestinationExists is false, the library deletes the stray file and throws instead of silently returning a differently-named document. It protects callers who need the exact name they asked for.
Solutions
- Pass replaceIfDestinationExists=true if overwriting the existing destination is acceptable
- Include the correct extension in fileName matching the mimeType (e.g. 'notes.txt' for text/plain) so the provider doesn't append one
- Check for the file's existence first (statFile) and pick a unique name before creating
- Catch the error and read the requested vs actual names from the message to reconcile your UI/state
Example fix
// before await Safx.createFile(treeUri, 'notes', 'text/plain'); // provider creates 'notes.txt' -> throws // after await Safx.createFile(treeUri, 'notes.txt', 'text/plain', true);
Defensive patterns
Strategy: try-catch
Validate before calling
const existing = await Safx.statFile(treeUri, fileName);
if (existing) {
// either replace intentionally or pick a new unique name
}
const nameWithExt = /\.[a-z0-9]+$/i.test(fileName) ? fileName : `${fileName}.txt`; // match the mimeType Type guard
const resolvesToRequestedName = async (treeUri: string, fileName: string) => {
try { const s = await Safx.statFile(treeUri, fileName); return !!s && !s.isDirectory; } catch { return false; }
}; Try / catch
try {
const uri = await Safx.createFile(treeUri, fileName, mimeType);
} catch (e) {
if (String(e?.message).startsWith('The created file name was not as expected')) {
// retry with replaceIfDestinationExists=true or a unique name including the correct extension
}
throw e;
} Prevention
- Always include the extension matching the mimeType in fileName
- Use replaceIfDestinationExists=true when overwriting is acceptable
- Pre-generate unique names (uuid/timestamp) to avoid provider-side collision renames
When it happens
Trigger: Calling createFile/createFileInDirectory with replaceIfDestinationExists=false while name-mangling occurs: (1) target file already exists and the provider renamed the new document instead of failing, (2) the provider appends an extension for the MIME type (e.g. requesting 'notes' with mime text/plain creates 'notes.txt'), (3) provider-side normalization changes the name.
Common situations: Creating a file in a folder where the name already exists (collision dedupe by the provider); omitting the extension in the name while providing a MIME type so the provider appends it; OEM storage providers behaving differently from the AOSP DocumentsProvider.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- The created file name was not as expected and the existing…
- Invalid file name: Could not extract filename from uri…
- a file or directory already exist at
- could not create file at
- Cannot find unique filename
AI-assisted analysis of laurent22/joplin@981a03c5c9 (2026-09-17).
Data as JSON: /api/errors/da25b30103dac228.
Report an issue: GitHub.
Appendix: source
Thrown at packages/react-native-saf-x/android/src/main/java/com/reactnativesafx/utils/EfficientDocumentHelper.java:480
);
if (createdFile == null) {
throw new IOExceptionFast(
"File creation failed without any specific error for '" + fileName + "'");
}
String createdFileName = UriHelper.getFileName(createdFile.toString());
if (!createdFileName.equals(fileName)) {
// A provider can change the name when a document with the requested name
// already exists. Do not try to rename this document into the occupied
// destination: a rename can partially succeed before reporting an error.
// Delete the document returned by this create call. Replacement-capable
// callers can then resolve and overwrite the intended destination;
// create-only callers retain their collision failure semantics.
unlink(createdFile);
if (!replaceIfDestinationExists) {
throw new IOExceptionFast(
"The created file name was not as expected: input name was '"
+ fileName
+ "' but got: '"
+ createdFileName
+ "'");
}
DocumentStat existingFile = findFile(parentDirOfFile, fileName);
if (existingFile == null || existingFile.isDirectory()) {
throw new IOExceptionFast(
"The created file name was not as expected and the existing destination could not be resolved: input name was '"
+ fileName
+ "' but got: '"
+ createdFileName
+ "'");
}
return existingFile.getInternalUri();
}
View on GitHub (pinned to 981a03c5c9)