{"record":{"id":"c5be153ac0f0c080","repo":"gildas-lormeau/SingleFile","slug":"error-message-github","errorCode":null,"errorMessage":"error.message + \" (GitHub)\"","messagePattern":"error\\.message \\+ \" \\(GitHub\\)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/core/bg/downloads.js","lineNumber":482,"sourceCode":"\t\tif (authInfo) {\n\t\t\tawait config.setDropboxAuthInfo(authInfo);\n\t\t} else {\n\t\t\tawait config.removeDropboxAuthInfo();\n\t\t}\n\t}\n\treturn authInfo;\n}\n\nasync function saveToGitHub(taskId, filename, content, githubToken, githubUser, githubRepository, githubBranch, { filenameConflictAction, prompt }) {\n\ttry {\n\t\tconst taskInfo = business.getTaskInfo(taskId);\n\t\tif (!taskInfo || !taskInfo.cancelled) {\n\t\t\tconst client = new GitHub(githubToken, githubUser, githubRepository, githubBranch);\n\t\t\tbusiness.setCancelCallback(taskId, () => client.abort());\n\t\t\treturn await client.upload(filename, content, { filenameConflictAction, prompt });\n\t\t}\n\t} catch (error) {\n\t\tthrow new Error(error.message + \" (GitHub)\", { cause: error });\n\t}\n}\n\nasync function saveToS3(taskId, filename, blob, domain, region, bucket, accessKey, secretKey, { filenameConflictAction, prompt }) {\n\ttry {\n\t\tconst taskInfo = business.getTaskInfo(taskId);\n\t\tif (!taskInfo || !taskInfo.cancelled) {\n\t\t\tconst client = new S3(region, bucket, accessKey, secretKey, domain);\n\t\t\tbusiness.setCancelCallback(taskId, () => client.abort());\n\t\t\treturn await client.upload(filename, blob, { filenameConflictAction, prompt });\n\t\t}\n\t} catch (error) {\n\t\tthrow new Error(error.message + \" (S3)\", { cause: error });\n\t}\n}\n\nasync function saveWithWebDAV(taskId, filename, content, url, username, password, { filenameConflictAction, prompt }) {\n\ttry {","sourceCodeStart":464,"sourceCodeEnd":500,"githubUrl":"https://github.com/gildas-lormeau/SingleFile/blob/517fb7c5cf2096d89933b747e862d8ecf616a9f9/src/core/bg/downloads.js#L464-L500","documentation":"saveToGitHub wraps any error thrown while uploading a captured page to a GitHub repository via the GitHub client (client.upload). It rethrows the underlying message with an \" (GitHub)\" suffix and keeps the original error as cause. The suffix tells the caller which save destination failed.","triggerScenarios":"Any failure inside new GitHub(token, user, repo, branch).upload(filename, content, {filenameConflictAction, prompt}) invoked from downloadContent/downloadCompressedContent, including invalid token, bad repo/branch, network failure, or abort/cancel errors.","commonSituations":"Expired or revoked GitHub personal access token; repository or branch renamed/deleted; token lacking repo scope; filename conflicts requiring user prompt in a background context where prompting is unavailable; offline network.","solutions":["Inspect error.cause for the original message and verify the GitHub token is valid and has repo write scope","Confirm githubUser, githubRepository and githubBranch exist and match exactly (case-sensitive)","Check network connectivity and retry the save","Set filenameConflictAction to 'overwrite' or 'uniquify' to avoid conflict-prompt failures"],"exampleFix":"// before\nthrow new Error('upload failed: 401 Bad credentials');\n// after\n// wrapper adds context; fix root cause by refreshing the token:\n// const client = new GitHub(await getFreshToken(), user, repo, branch);","handlingStrategy":"try-catch","validationCode":"// before calling save\nif (!githubToken || !githubUser || !githubRepository || !githubBranch) {\n  throw new Error('Missing GitHub save configuration');\n}","typeGuard":"function hasGithubConfig(o) {\n  return typeof o.token === 'string' && o.token.length > 0 &&\n    typeof o.user === 'string' && typeof o.repo === 'string' && typeof o.branch === 'string';\n}","tryCatchPattern":"try {\n  await saveToGitHub(taskId, filename, content, githubOpts);\n} catch (error) {\n  if (error.message.endsWith('(GitHub)')) {\n    console.error('GitHub save failed:', error.cause);\n  } else { throw error; }\n}","preventionTips":["Validate the GitHub token with a cheap API call (GET /user) at config time","Verify repo and branch exist before batch saves","Set filenameConflictAction explicitly to avoid prompt-dependent failures","Always inspect error.cause to reach the root cause"],"tags":["github","upload","error-wrapping","network"],"backgroundTag":"github-upload-failed","analyzedSha":"517fb7c5cf2096d89933b747e862d8ecf616a9f9","analyzedAt":"2026-09-01T10:05:25.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}