{"record":{"id":"486ab76cd9cf8f5e","repo":"RocketChat/Rocket.Chat","slug":"marketplace-bad-marketplace-connection-486ab7","errorCode":null,"errorMessage":"Marketplace_Bad_Marketplace_Connection","messagePattern":"Marketplace_Bad_Marketplace_Connection","errorType":"error_code","errorClass":"MarketplaceConnectionError","httpStatus":null,"severity":"error","filePath":"apps/meteor/ee/server/apps/marketplace/fetchMarketplaceCategories.ts","lineNumber":51,"sourceCode":"\tif (token) {\n\t\theaders.Authorization = `Bearer ${token}`;\n\t}\n\n\tlet request;\n\ttry {\n\t\trequest = await Apps.getMarketplaceClient().fetch(`v1/categories`, {\n\t\t\theaders,\n\t\t\tignoreSsrfValidation: false,\n\t\t\tallowList: settings.get<string>('SSRF_Allowlist'),\n\t\t});\n\t} catch (error) {\n\t\t// Offline (air-gapped) licenses reject before any request is made; keep the\n\t\t// typed error so the REST layer can report the real reason instead of a\n\t\t// generic connectivity failure.\n\t\tif (error instanceof CloudOfflineLicenseError) {\n\t\t\tthrow error;\n\t\t}\n\t\tthrow new MarketplaceConnectionError('Marketplace_Bad_Marketplace_Connection');\n\t}\n\n\tif (request.status === 200) {\n\t\tconst response = await request.json();\n\t\tfetchMarketplaceCategoriesSchema.parse(response);\n\t\treturn response;\n\t}\n\n\tconst response = await request.json();\n\n\tApps.getRocketChatLogger().error({ msg: 'Error fetching marketplace categories', status: request.status, response });\n\n\t// TODO: Refactor cloud to return a proper error code on unsupported version\n\tif (request.status === 426 && 'errorMsg' in response && response.errorMsg === 'unsupported version') {\n\t\tthrow new MarketplaceUnsupportedVersionError();\n\t}\n\n\tconst INTERNAL_MARKETPLACE_ERROR_CODES = [189, 266];","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/ee/server/apps/marketplace/fetchMarketplaceCategories.ts#L33-L69","documentation":"Thrown by fetchMarketplaceCategories when the marketplace client fetch to v1/categories throws at the network level. Same pattern as the apps variant: CloudOfflineLicenseError is rethrown as-is; any other throw becomes MarketplaceConnectionError('Marketplace_Bad_Marketplace_Connection'). HTTP error statuses are handled downstream, not here.","triggerScenarios":"Calling fetchMarketplaceCategories() with no network route to the marketplace, DNS failure, TLS handshake failure, or request abort. The offline-license branch fires when an air-gapped license blocks the call before it is made.","commonSituations":"Air-gapped deployment; proxy/firewall blocking the marketplace host; SSRF_Allowlist misconfiguration; DNS outage; offline license in an online-expected flow.","solutions":["Verify outbound network access to the marketplace host.","Configure HTTPS_PROXY if behind a corporate proxy and restart.","Add the marketplace host to SSRF_Allowlist if SSRF validation applies.","Handle CloudOfflineLicenseError separately if running an offline license intentionally.","Retry after restoring connectivity."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"async function canReachMarketplaceHost(): Promise<boolean> {\n  try {\n    await Apps.getMarketplaceClient().fetch('v1/categories', { ignoreSsrfValidation: false });\n    return true;\n  } catch { return false; }\n}","typeGuard":"import { MarketplaceConnectionError } from './marketplaceErrors';\nimport { CloudOfflineLicenseError } from '../../../../lib/errors/CloudOfflineLicenseError';\n\nconst isMarketplaceConnectionError = (e: unknown): e is MarketplaceConnectionError =>\n  e instanceof MarketplaceConnectionError;\n\nconst isOfflineLicenseError = (e: unknown): e is CloudOfflineLicenseError =>\n  e instanceof CloudOfflineLicenseError;","tryCatchPattern":"try {\n  return await fetchMarketplaceCategories();\n} catch (e) {\n  if (e instanceof CloudOfflineLicenseError) return [];\n  if (e instanceof MarketplaceConnectionError) {\n    return await retryWithBackoff(() => fetchMarketplaceCategories());\n  }\n  throw e;\n}","preventionTips":["Verify egress and proxy config before relying on marketplace categories.","Add the marketplace host to SSRF_Allowlist if SSRF validation applies.","Distinguish CloudOfflineLicenseError from real connectivity failures.","Cache categories locally since they change infrequently."],"tags":["marketplace","network","connection","categories","ssrf"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}