{"record":{"id":"9e7b1cb46db86f34","repo":"FlowiseAI/Flowise","slug":"failed-to-refresh-access-token-error-instanceof","errorCode":null,"errorMessage":"Failed to refresh access token: ${error instanceof Error ? error.message : 'Unknown error'}. Please re-authorize the credential.","messagePattern":"Failed to refresh access token: (.+?)\\. Please re-authorize the credential\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/components/src/utils.ts","lineNumber":1498,"sourceCode":"                            'Content-Type': 'application/json'\n                        }\n                    }\n                )\n\n                if (!refreshResponse.ok) {\n                    const errorData = await refreshResponse.text()\n                    throw new Error(`Failed to refresh token: ${refreshResponse.status} ${refreshResponse.statusText} - ${errorData}`)\n                }\n\n                await refreshResponse.json()\n\n                // Get the updated credential data\n                const updatedCredentialData = await getCredentialData(credentialId, options)\n\n                return updatedCredentialData\n            } catch (error) {\n                console.error('Failed to refresh access token:', error)\n                throw new Error(\n                    `Failed to refresh access token: ${\n                        error instanceof Error ? error.message : 'Unknown error'\n                    }. Please re-authorize the credential.`\n                )\n            }\n        }\n    }\n\n    // Token is not expired, return original data\n    return credentialData\n}\n\nexport const stripHTMLFromToolInput = (input: string) => {\n    const turndownService = new TurndownService()\n    let cleanedInput = turndownService.turndown(input)\n    // After conversion, replace any escaped underscores and square brackets with regular unescaped ones\n    cleanedInput = cleanedInput.replace(/\\\\([_[\\]])/g, '$1')\n    return cleanedInput","sourceCodeStart":1480,"sourceCodeEnd":1516,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/components/src/utils.ts#L1480-L1516","documentation":"Outer catch-all in the OAuth2 refresh try block. Any exception thrown inside the refresh flow (the non-ok throw above, a network error from fetch, a JSON parse error, or getCredentialData failure) is rewrapped with this message and 'Please re-authorize the credential.' It deliberately loses the distinction between network failures and provider rejections.","triggerScenarios":"node-fetch throws TypeError (DNS failure, connection refused to the refresh endpoint); the inner throw from a non-ok response propagates here; refreshResponse.json() throws because the body isn't JSON; getCredentialData(credentialId, options) throws because the credential was concurrently deleted; the dynamic import('node-fetch') fails because the dependency isn't installed.","commonSituations":"Flowise API server unreachable at refresh time (wrong baseURL, server down); node-fetch not in dependencies after a refactor; concurrent credential deletion; transient network blips being treated as permanent auth failures.","solutions":["Distinguish transient failures (network/timeout) from permanent ones (invalid_grant) — only advise re-authorization for permanent failures.","Confirm options.baseURL resolves and the Flowise API is reachable from the process running refreshOAuth2Token.","Ensure node-fetch is installed (or switch to global fetch on Node >= 18).","Inspect the cause/inner message already embedded in the thrown string to pick the right fix."],"exampleFix":"// before\n} catch (error) {\n  console.error('Failed to refresh access token:', error)\n  throw new Error(`Failed to refresh access token: ${error instanceof Error ? error.message : 'Unknown error'}. Please re-authorize the credential.`)\n}\n\n// after — only demand re-auth for permanent failures; retry/propagate transient ones\n} catch (error) {\n  const msg = error instanceof Error ? error.message : String(error)\n  const isPermanent = /invalid_grant|invalid_client|unauthorized|401|400/.test(msg)\n  if (isPermanent) {\n    throw new Error(`Failed to refresh access token: ${msg}. Please re-authorize the credential.`)\n  }\n  throw new Error(`Transient failure refreshing access token for ${credentialId}: ${msg}`, { cause: error })\n}","handlingStrategy":"retry","validationCode":"function isTransientRefreshError(msg: string): boolean {\n  return /ETIMEDOUT|ECONNREFUSED|ENOTFOUND|fetch failed|network|5\\d\\d/i.test(msg) && !/invalid_grant/.test(msg)\n}","typeGuard":"function isNodeFetchTypeError(e: unknown): boolean {\n  return e instanceof TypeError && /fetch|network|socket/i.test(e.message)\n}","tryCatchPattern":"} catch (error) {\n  const msg = error instanceof Error ? error.message : String(error)\n  if (isTransientRefreshError(msg)) {\n    // retry with backoff, do NOT tell the user to re-authorize\n    throw new Error(`Transient token refresh failure: ${msg}`, { cause: error })\n  }\n  throw new Error(`Failed to refresh access token: ${msg}. Please re-authorize the credential.`)\n}","preventionTips":["Use Node >= 18 global fetch or guarantee node-fetch is installed.","Retry transient network failures before declaring the credential dead.","Separate permanent (invalid_grant) from transient (network) failures in error messages."],"tags":["oauth2","refresh","error-wrapping","auth","network"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}