{"record":{"id":"a959414910f4c769","repo":"NousResearch/hermes-agent","slug":"could-not-refresh-the-remote-gateway-websocket-tic","errorCode":null,"errorMessage":"Could not refresh the remote gateway WebSocket ticket.","messagePattern":"Could not refresh the remote gateway WebSocket ticket\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/shared/src/websocket-url.ts","lineNumber":66,"sourceCode":"    try {\n      const result = await mint(profile)\n\n      if (typeof result === 'string') {\n        return result\n      }\n\n      if (result.ok) {\n        return result.wsUrl\n      }\n\n      if (result.needsOauthLogin) {\n        throw new GatewayReauthRequiredError(\n          'Your remote gateway session has expired. Open Settings -> Gateway and click \"Sign in\" again.',\n          { cause: new Error(result.error) }\n        )\n      }\n\n      throw new Error(result.error || 'Could not refresh the remote gateway WebSocket ticket.')\n    } catch (error) {\n      if (isGatewayReauthRequired(error)) {\n        throw error instanceof GatewayReauthRequiredError\n          ? error\n          : new GatewayReauthRequiredError(\n              'Your remote gateway session has expired. Open Settings -> Gateway and click \"Sign in\" again.',\n              { cause: error }\n            )\n      }\n\n      throw error\n    }\n  }\n\n  if (mint) {\n    const fresh = await mint(profile).catch(() => null)\n\n    if (typeof fresh === 'string') {","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/apps/shared/src/websocket-url.ts#L48-L84","documentation":"The generic failure thrown by resolveGatewayWsUrl when ticket minting completed without ok, without needsOauthLogin, and the backend supplied no error string — i.e. the mint endpoint answered, but the response was an unrecognized failure shape. It is the last-resort branch for OAuth ticket refresh when nothing more specific applies.","triggerScenarios":"getGatewayWsUrl returns { ok: false } with an empty/missing error field — backend ticket endpoint down or returning an unexpected body, or a shape change in the ticket API between app and backend versions.","commonSituations":"Remote gateway mid-restart when the ticket route is unavailable, reverse proxy returning HTML that got parsed into an empty failure, or version drift between apps/shared and the gateway's ticket endpoint.","solutions":["Retry after confirming the remote gateway is up and reachable (its health/status route).","Check gateway logs for the ticket-mint request and its failure reason — the empty error hides it server-side.","Update both Desktop app and gateway to matching versions if the ticket response shape changed."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await resolveGatewayWsUrl(deps, conn)\n} catch (e) {\n  if (isGatewayReauthRequiredError(e)) throw e\n  if (e instanceof Error && e.message.includes('Could not refresh')) {\n    await backoffRetry(2) // transient backend/proxy hiccup\n  } else throw e\n}","preventionTips":["Distinguish this generic failure from reauth-required before retrying or prompting.","Log the raw mint response body when it has no error field — the cause is server-side.","Version-align app and gateway so ticket response shapes stay compatible."],"tags":["oauth","websocket","gateway","shared","retry"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}