{"record":{"id":"4b5bec99454e9c72","repo":"laurent22/joplin","slug":"s3uploadfilefrom-file-does-not-exist","errorCode":null,"errorMessage":"s3UploadFileFrom: file does not exist","messagePattern":"s3UploadFileFrom: file does not exist","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/lib/file-api-driver-amazon-s3.js","lineNumber":102,"sourceCode":"\t\t\t});\n\t\t});\n\t}\n\n\tasync s3PutObject(key, body) {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.api().send(new PutObjectCommand({\n\t\t\t\tBucket: this.s3_bucket_,\n\t\t\t\tKey: key,\n\t\t\t\tBody: body,\n\t\t\t}), (error, response) => {\n\t\t\t\tif (error) reject(error);\n\t\t\t\telse resolve(response);\n\t\t\t});\n\t\t});\n\t}\n\n\tasync s3UploadFileFrom(path, key) {\n\t\tif (!shim.fsDriver().exists(path)) throw new Error('s3UploadFileFrom: file does not exist');\n\t\tconst body = await shim.fsDriver().readFile(path, 'base64');\n\t\tconst fileStat = await shim.fsDriver().stat(path);\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.api().send(new PutObjectCommand({\n\t\t\t\tBucket: this.s3_bucket_,\n\t\t\t\tKey: key,\n\t\t\t\tBody: Buffer.from(body, 'base64'),\n\t\t\t\tContentLength: `${fileStat.size}`,\n\t\t\t}), (error, response) => {\n\t\t\t\tif (error) reject(error);\n\t\t\t\telse resolve(response);\n\t\t\t});\n\t\t});\n\t}\n\n\tasync s3DeleteObject(key) {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.api().send(new DeleteObjectCommand({","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/lib/file-api-driver-amazon-s3.js#L84-L120","documentation":"Thrown by FileApiDriverAmazonS3.s3UploadFileFrom() when shim.fsDriver().exists(path) returns false before attempting to read and upload the local file. The function is used when options.source === 'file' on a put() call — the sync engine is trying to upload a resource file (e.g. an attachment body) whose local path no longer exists.","triggerScenarios":"The sync engine calls driver.put(path, null, { source: 'file', path: localPath }) to upload a resource, but the local file at localPath has been deleted, moved, or was never written to disk. s3UploadFileFrom checks existence and throws immediately.","commonSituations":"A resource's blob file was deleted from the resource directory (manual cleanup, disk cleanup tool); the file is on external/removable storage that was unmounted; a previous operation failed to write the blob; race between resource deletion and sync.","solutions":["Verify the local resource file still exists at the expected path in the Joplin resources directory.","If the resource was intentionally deleted, remove its metadata so sync doesn't try to upload it, or let sync reconcile the deletion.","Restore the missing file from backup if the resource should still exist.","Check for disk/storage issues (unmounted external storage, full disk) that prevented the file from being written."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import shim from './shim';\n// Before requesting an upload from a file\nif (!await shim.fsDriver().exists(localPath)) {\n  // the resource blob is gone; skip or reconcile the resource metadata\n  logger.warn('Resource file missing, skipping upload', localPath);\n  return;\n}","typeGuard":null,"tryCatchPattern":"try {\n  await driver.put(path, null, { source: 'file', path: localPath });\n} catch (error) {\n  if (/file does not exist/.test(error.message)) {\n    // reconcile: mark resource as deleted or restore from backup\n    return;\n  }\n  throw error;\n}","preventionTips":["Verify local resource files exist before attempting file-source uploads.","Avoid manual cleanup of the resources directory while sync is running.","Handle missing-file errors by reconciling resource metadata rather than failing the sync."],"tags":["s3","sync","resources","filesystem","upload"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}