{"record":{"id":"28ab290a8b4acb1e","repo":"gildas-lormeau/SingleFile","slug":"invalid-token","errorCode":"invalid_token","errorMessage":"invalid_token","messagePattern":"invalid_token","errorType":"error_code","errorClass":"Error","httpStatus":401,"severity":"error","filePath":"src/lib/gdrive/gdrive.js","lineNumber":489,"sourceCode":"}\n\nasync function getJSON(httpResponse) {\n\thttpResponse = getResponse(httpResponse);\n\tconst response = await httpResponse.json();\n\tif (response.error) {\n\t\tthrow new Error(response.error);\n\t} else {\n\t\treturn response;\n\t}\n}\n\nfunction getResponse(httpResponse) {\n\tif (httpResponse.status == 200) {\n\t\treturn httpResponse;\n\t} else if (httpResponse.status == 404) {\n\t\tthrow new Error(\"path_not_found\");\n\t} else if (httpResponse.status == 401) {\n\t\tthrow new Error(\"invalid_token\");\n\t} else {\n\t\tthrow new Error(\"unknown_error (\" + httpResponse.status + \")\");\n\t}\n}\n","sourceCodeStart":471,"sourceCodeEnd":494,"githubUrl":"https://github.com/gildas-lormeau/SingleFile/blob/517fb7c5cf2096d89933b747e862d8ecf616a9f9/src/lib/gdrive/gdrive.js#L471-L494","documentation":"getResponse converts an HTTP 401 from the Drive API into \"invalid_token\". This means the OAuth access token sent with the request is missing, expired, or revoked, so the API rejected the request as unauthenticated. It is the library's normalized signal that the caller must re-authenticate.","triggerScenarios":"Access token expired (Google tokens last ~1 hour); user revoked the app in their Google account settings; token never attached to the request; refresh flow failed silently but a stale token is still used.","commonSituations":"Long-running jobs that outlive token lifetime without refreshing; users revoking access then the app retrying with cached tokens; clock skew on the host invalidating freshly issued tokens; switching accounts without clearing stored credentials.","solutions":["Catch the error and re-run the auth flow (gdrive.auth) to obtain a fresh token, then retry the request once.","Verify the stored token is still valid by checking expiry before requests; refresh proactively.","If refresh fails, clear stored credentials and require interactive re-consent.","Confirm the Authorization header is actually included in requests made outside the library's helpers."],"exampleFix":"// before\nconst data = await gdrive.getJSON(resp); // 401 -> invalid_token\n// after\ntry {\n  var data = await gdrive.getJSON(resp);\n} catch (e) {\n  if (e.message === \"invalid_token\") {\n    await gdrive.auth(options); // refresh\n    data = await gdrive.getJSON(resp);\n  } else throw e;\n}","handlingStrategy":"retry","validationCode":"function tokenLikelyValid(auth) {\n  return auth && typeof auth.accessToken === \"string\" &&\n    (!auth.expiry || Date.now() < auth.expiry - 60_000); // refresh 1min early\n}","typeGuard":null,"tryCatchPattern":"try { return await callGdrive(); }\ncatch (e) {\n  if (e.message === \"invalid_token\") {\n    await gdrive.auth(options); // force re-auth/refresh\n    return await callGdrive(); // retry once\n  }\n  throw e;\n}","preventionTips":["Refresh tokens proactively before the ~1h expiry","Clear cached credentials when the user switches accounts","Handle revocation: catch invalid_token and re-consent rather than looping","Check host clock skew if tokens expire immediately"],"tags":["http-401","oauth","token-expired","gdrive"],"backgroundTag":"oauth-token-invalid","analyzedSha":"517fb7c5cf2096d89933b747e862d8ecf616a9f9","analyzedAt":"2026-09-01T10:05:25.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}