{"record":{"id":"6e00d5051770f3bb","repo":"ToolJet/ToolJet","slug":"connection-test-failed-6e00d5","errorCode":null,"errorMessage":"Connection test failed","messagePattern":"Connection test failed","errorType":"exception","errorClass":"QueryError","httpStatus":null,"severity":"error","filePath":"marketplace/plugins/hugging_face/lib/index.ts","lineNumber":66,"sourceCode":"\n    try {\n      const response = await fetch('https://huggingface.co/api/whoami-v2', {\n        method: 'GET',\n        headers: {\n          Authorization: `Bearer ${personal_access_token}`,\n          'Content-Type': 'application/json',\n        },\n      });\n\n      if (!response.ok) {\n        throw new Error(`API responded with status ${response.status}`);\n      }\n\n      return {\n        status: 'ok',\n      };\n    } catch (error) {\n      throw new QueryError(\n        'Connection test failed',\n        'Could not establish connection to Hugging Face API. Please check your credentials.',\n        {}\n      );\n    }\n  }\n}\n","sourceCodeStart":48,"sourceCodeEnd":74,"githubUrl":"https://github.com/ToolJet/ToolJet/blob/20602a8e101f2e59686c9afde0d1402aac2c8871/marketplace/plugins/hugging_face/lib/index.ts#L48-L74","documentation":"testConnection()'s outer catch swallows every error — including the informative 'API responded with status N' from error 153 — and re-throws a generic QueryError('Connection test failed', 'Could not establish connection to Hugging Face API. Please check your credentials.', {}). This destroys the HTTP status and original message, so callers cannot distinguish 401 (bad token) from 429 (rate limit) from network failure. data is always {}, giving the caller no structured context.","triggerScenarios":"Any throw inside testConnection's try: response.ok false (error 153), fetch network/DNS failure, response.json parse failure, or an unexpected exception. The catch is unconditional.","commonSituations":"Operator clicks 'Test Connection' and sees only a generic credentials hint despite the real cause being rate-limiting, network outage, or a temporary HF API incident; support tickets escalate because the message points to credentials when the issue is elsewhere.","solutions":["Patch the catch to preserve error.message and include structured data (HTTP status, error type) so callers can diagnose.","Distinguish error shapes before wrapping: HTTPError/non-OK (preserve status), TypeError/network (report connectivity), other (report unknown).","In the caller, treat 'Connection test failed' as a generic flag and re-run with verbose logging on the plugin side to recover the real cause.","Add a retry with backoff for transient (429/5xx/network) failures before declaring the connection failed."],"exampleFix":"// before — destroys the inner cause\n} catch (error) {\n  throw new QueryError(\n    'Connection test failed',\n    'Could not establish connection to Hugging Face API. Please check your credentials.',\n    {}\n  );\n}\n\n// after — preserve the original message and status\n} catch (error) {\n  throw new QueryError(\n    'Connection test failed',\n    error?.message ?? 'Could not establish connection to Hugging Face API. Please check your credentials.',\n    { status: error?.status, name: error?.name }\n  );\n}","handlingStrategy":"try-catch","validationCode":"// Nothing the caller can validate that the plugin cannot; mitigate by patching the\n// catch to preserve the inner error.\nfunction patchTestConnection(plugin) {\n  const orig = plugin.testConnection.bind(plugin);\n  plugin.testConnection = async (so) => {\n    try { return await orig(so); }\n    catch (e) {\n      // re-tag with whatever inner message we can recover\n      throw new Error(`HF test failed: ${e.description ?? e.message}`);\n    }\n  };\n}","typeGuard":"function isHfConnectionTestFailure(e): boolean {\n  return e?.name === 'QueryError' && e?.message === 'Connection test failed';\n}","tryCatchPattern":"try {\n  await hf.testConnection(sourceOptions);\n} catch (e) {\n  if (e.name === 'QueryError' && e.message === 'Connection test failed') {\n    // Description is generic; perform a direct whoami-v2 call to recover the status:\n    const r = await fetch('https://huggingface.co/api/whoami-v2', {\n      headers: { Authorization: `Bearer ${sourceOptions.personal_access_token}` }\n    });\n    return { ok: r.ok, status: r.status };\n  }\n  throw e;\n}","preventionTips":["Patch the plugin's catch to preserve error.message and HTTP status.","Run a direct whoami-v2 call from your own code if you need the real status (the plugin discards it).","Add retry/backoff for transient (429/5xx) failures before declaring failure."],"tags":["hugging-face","error-wrapping","diagnostics","connection-test","tooljet"],"backgroundTag":null,"analyzedSha":"20602a8e101f2e59686c9afde0d1402aac2c8871","analyzedAt":"2026-08-13T05:58:54.221Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}