{"record":{"id":"da25b30103dac228","repo":"laurent22/joplin","slug":"the-created-file-name-was-not-as-expected-input-name-was","errorCode":null,"errorMessage":"The created file name was not as expected: input name was '${fileName}' but got: '${createdFileName}'","messagePattern":"The created file name was not as expected: input name was '(.+?)' but got: '(.+?)'","errorType":"exception","errorClass":"IOExceptionFast","httpStatus":null,"severity":"error","filePath":"packages/react-native-saf-x/android/src/main/java/com/reactnativesafx/utils/EfficientDocumentHelper.java","lineNumber":480,"sourceCode":"    );\n\n    if (createdFile == null) {\n      throw new IOExceptionFast(\n        \"File creation failed without any specific error for '\" + fileName + \"'\");\n    }\n\n    String createdFileName = UriHelper.getFileName(createdFile.toString());\n\n    if (!createdFileName.equals(fileName)) {\n      // A provider can change the name when a document with the requested name\n      // already exists. Do not try to rename this document into the occupied\n      // destination: a rename can partially succeed before reporting an error.\n      // Delete the document returned by this create call. Replacement-capable\n      // callers can then resolve and overwrite the intended destination;\n      // create-only callers retain their collision failure semantics.\n      unlink(createdFile);\n      if (!replaceIfDestinationExists) {\n        throw new IOExceptionFast(\n          \"The created file name was not as expected: input name was '\"\n            + fileName\n            + \"' but got: '\"\n            + createdFileName\n            + \"'\");\n      }\n      DocumentStat existingFile = findFile(parentDirOfFile, fileName);\n      if (existingFile == null || existingFile.isDirectory()) {\n        throw new IOExceptionFast(\n          \"The created file name was not as expected and the existing destination could not be resolved: input name was '\"\n            + fileName\n            + \"' but got: '\"\n            + createdFileName\n            + \"'\");\n      }\n      return existingFile.getInternalUri();\n    }\n","sourceCodeStart":462,"sourceCodeEnd":498,"githubUrl":"https://github.com/laurent22/joplin/blob/981a03c5c9e88130bccff4db47c411d35ec7ae2c/packages/react-native-saf-x/android/src/main/java/com/reactnativesafx/utils/EfficientDocumentHelper.java#L462-L498","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nawait Safx.createFile(treeUri, 'notes', 'text/plain'); // provider creates 'notes.txt' -> throws\n// after\nawait Safx.createFile(treeUri, 'notes.txt', 'text/plain', true);","handlingStrategy":"try-catch","validationCode":"const existing = await Safx.statFile(treeUri, fileName);\nif (existing) {\n\t// either replace intentionally or pick a new unique name\n}\nconst nameWithExt = /\\.[a-z0-9]+$/i.test(fileName) ? fileName : `${fileName}.txt`; // match the mimeType","typeGuard":"const resolvesToRequestedName = async (treeUri: string, fileName: string) => {\n\ttry { const s = await Safx.statFile(treeUri, fileName); return !!s && !s.isDirectory; } catch { return false; }\n};","tryCatchPattern":"try {\n\tconst uri = await Safx.createFile(treeUri, fileName, mimeType);\n} catch (e) {\n\tif (String(e?.message).startsWith('The created file name was not as expected')) {\n\t\t// retry with replaceIfDestinationExists=true or a unique name including the correct extension\n\t}\n\tthrow e;\n}","preventionTips":["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"],"tags":["android","saf","filename","collision"],"backgroundTag":"internal-invariant-violation","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"}