{"record":{"id":"5d4f42ace38dd0ec","repo":"gildas-lormeau/SingleFile","slug":"error-message-dropbox","errorCode":null,"errorMessage":"error.message + \" (Dropbox)\"","messagePattern":"error\\.message \\+ \" \\(Dropbox\\)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/core/bg/downloads.js","lineNumber":574,"sourceCode":"\nasync function saveToDropbox(taskId, filename, blob, uploadOptions) {\n\ttry {\n\t\tawait getDropboxAuthInfo();\n\t\tconst taskInfo = business.getTaskInfo(taskId);\n\t\tif (!taskInfo || !taskInfo.cancelled) {\n\t\t\treturn await dropbox.upload(filename, blob, uploadOptions, callback => business.setCancelCallback(taskId, callback));\n\t\t}\n\t}\n\tcatch (error) {\n\t\tif (error.message == \"invalid_token\") {\n\t\t\tlet authInfo;\n\t\t\ttry {\n\t\t\t\tauthInfo = await dropbox.refreshAuthToken();\n\t\t\t} catch (error) {\n\t\t\t\tif (error.message == \"unknown_token\") {\n\t\t\t\t\tauthInfo = await getDropboxAuthInfo(true);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(error.message + \" (Dropbox)\", { cause: error });\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (authInfo) {\n\t\t\t\tawait config.setDropboxAuthInfo(authInfo);\n\t\t\t} else {\n\t\t\t\tawait config.removeDropboxAuthInfo();\n\t\t\t}\n\t\t\treturn await saveToDropbox(taskId, filename, blob, uploadOptions);\n\t\t} else {\n\t\t\tthrow new Error(error.message + \" (Dropbox)\", { cause: error });\n\t\t}\n\t}\n}\n\nasync function testSkipSave(filename, options) {\n\tlet skipped, filenameConflictAction = options.filenameConflictAction;\n\tif (filenameConflictAction == CONFLICT_ACTION_SKIP) {\n\t\tconst downloadItems = await browser.downloads.search({","sourceCodeStart":556,"sourceCodeEnd":592,"githubUrl":"https://github.com/gildas-lormeau/SingleFile/blob/517fb7c5cf2096d89933b747e862d8ecf616a9f9/src/core/bg/downloads.js#L556-L592","documentation":"In saveToDropbox, when refreshing the Dropbox OAuth token fails with any message other than \"unknown_token\", the error is rethrown with an \" (Dropbox)\" suffix and the original as cause. It signals a non-recoverable Dropbox token refresh failure.","triggerScenarios":"dropbox.refreshAuthToken() rejects during saveToDropbox (called from downloadContent/downloadCompressedContent) with errors like 'invalid_grant'; only 'unknown_token' triggers re-auth.","commonSituations":"User disconnected SingleFile from Dropbox app connections; refresh token expired; Dropbox app credentials changed; Dropbox API outage.","solutions":["Reconnect Dropbox in SingleFile options to get fresh auth tokens","Check error.cause for the OAuth error code (invalid_grant means re-consent required)","Verify system clock accuracy","Check https://www.dropbox.com/account/connected_apps and revoke/re-add if stale"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// verify stored Dropbox auth before saving\nconst authInfo = await config.getDropboxAuthInfo();\nif (!authInfo || !authInfo.refreshToken) {\n  await getDropboxAuthInfo(true); // force interactive re-auth\n}","typeGuard":null,"tryCatchPattern":"try {\n  await saveToDropbox(taskId, filename, blob, uploadOptions);\n} catch (error) {\n  if (error.message.endsWith('(Dropbox)') && String(error.cause).includes('invalid_grant')) {\n    await getDropboxAuthInfo(true); // force re-consent\n  } else { throw error; }\n}","preventionTips":["Reconnect Dropbox in app settings periodically","Do not revoke SingleFile in Dropbox connected-apps settings","Keep system clock synchronized","Treat 'invalid_grant' in error.cause as needing re-consent"],"tags":["dropbox","oauth","token-refresh","error-wrapping"],"backgroundTag":"oauth-token-refresh-failed","analyzedSha":"517fb7c5cf2096d89933b747e862d8ecf616a9f9","analyzedAt":"2026-09-01T10:05:25.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}