ruvnet/ruflo · error · OAuthError

network

network

Error message

network error: ${e instanceof Error ? e.message : String(e)}

What it means

postForm wraps fetch for POST /oauth/token; any thrown fetch exception (DNS failure, ECONNREFUSED, TLS error, proxy refusal) is normalized to OAuthError code 'network' carrying the underlying message. The request never got an HTTP response — this is transport-level failure, not an OAuth decision.

Source

Thrown at v3/@claude-flow/security/src/oauth/client.ts:101

      body.error,
      body.error_description,
    );
  } catch (e) {
    if (e instanceof OAuthError) throw e;
    throw new OAuthError('unexpected response shape from the server', 'unexpected_shape');
  }
}

async function postForm(path: string, form: Record<string, string>, base = authBaseUrl()): Promise<TokenResponse> {
  let resp: Response;
  try {
    resp = await fetch(`${base}${path}`, {
      method: 'POST',
      headers: { 'content-type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams(form).toString(),
    });
  } catch (e) {
    throw new OAuthError(`network error: ${e instanceof Error ? e.message : String(e)}`, 'network');
  }
  return parseTokenResponse(resp);
}

/** `POST /oauth/token` with `grant_type=authorization_code`. */
export async function exchangeCode(
  code: string,
  codeVerifier: string,
  redirectUri: string,
  base = authBaseUrl(),
): Promise<TokenResponse> {
  return postForm(
    '/oauth/token',
    { grant_type: 'authorization_code', code, code_verifier: codeVerifier, client_id: CLIENT_ID, redirect_uri: redirectUri },
    base,
  );
}

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Check reachability: curl -v https://auth.cognitum.one/oauth/token — any HTTP status (even 4xx) means transport is fine
  2. Set HTTPS_PROXY/HTTP_PROXY (and NO_PROXY where needed) on proxied networks
  3. For private CAs: export NODE_EXTRA_CA_CERTS=/path/to/ca.pem
  4. Retry with backoff — transport failures are frequently transient

Example fix

# before: CI runner with no direct egress
# → network error: fetch failed

# after
export HTTPS_PROXY=http://proxy.corp:3128
export NO_PROXY=localhost,127.0.0.1
Defensive patterns

Strategy: retry

Validate before calling

async function authHostReachable(base: string): Promise<boolean> {
  try {
    await fetch(base, { method: 'HEAD' });
    return true; // any response means transport works
  } catch {
    return false;
  }
}
if (!(await authHostReachable(process.env.COGNITUM_AUTH_URL ?? 'https://auth.cognitum.one'))) {
  throw new Error('auth host unreachable — check network/proxy config');
}

Type guard

function isOAuthNetworkError(e: unknown): boolean {
  return e instanceof Error && e.name === 'OAuthError' && (e as { code?: string }).code === 'network';
}

Try / catch

for (let attempt = 1; attempt <= 3; attempt++) {
  try {
    return await exchangeCode(code, verifier, redirectUri);
  } catch (e) {
    if (isOAuthNetworkError(e) && attempt < 3) {
      await new Promise((r) => setTimeout(r, 500 * 2 ** attempt));
      continue;
    }
    throw e;
  }
}

Prevention

When it happens

Trigger: No DNS/route to auth.cognitum.one (offline sandbox); corporate network requiring HTTPS_PROXY that isn't set; COGNITUM_AUTH_URL pointing at an internal host with a self-signed cert Node doesn't trust; IPv6-only resolution breakage.

Common situations: CI jobs with no egress; forgotten proxy env vars on dev machines; private CAs missing from the Node trust store; transient DNS flakes on cloud runners.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/72b0f0597b856b4e. Report an issue: GitHub.