vercel/ai · error · APICallError

Cannot connect to API: ${cause.message}

Error message

Cannot connect to API: ${cause.message}

What it means

postToApi catches fetch exceptions thrown while POSTing a request body (JSON or form data) and rethrows them through handleFetchError as an APICallError: 'Cannot connect to API: <cause.message>' with isRetryable: true. This is the SDK's normalization of transport-level failures — the request never received an HTTP response from the provider endpoint.

Source

Thrown at packages/provider-utils/src/post-to-api.ts:164

      });
    } catch (error) {
      if (error instanceof Error) {
        if (isAbortError(error) || APICallError.isInstance(error)) {
          throw error;
        }
      }

      throw new APICallError({
        message: 'Failed to process successful response',
        cause: error,
        statusCode: response.status,
        url,
        responseHeaders,
        requestBodyValues: body.values,
      });
    }
  } catch (error) {
    throw handleFetchError({ error, url, requestBodyValues: body.values });
  }
};

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Inspect error.cause for the underlying code and fix accordingly: ECONNREFUSED → endpoint not running; ENOTFOUND → hostname typo; ETIMEDOUT/ECONNRESET → network/firewall/load balancer issue.
  2. Retry with exponential backoff — handleFetchError marks these isRetryable: true — or enable the SDK's maxRetries option (default 2).
  3. Verify the provider baseURL (createOpenAI({ baseURL }), Azure deployment URLs) resolves from your runtime.
  4. Configure proxy/dispatcher (undici ProxyAgent, HTTPS_PROXY) in corporate or containerized environments.
  5. Increase fetch timeouts for slow gateways (UND_ERR_HEADERS_TIMEOUT/BODY_TIMEOUT) via a custom undici Agent.

Example fix

// before
const openai = createOpenAI({ baseURL: 'http://localhost:8080/v1' });
// after (gateway actually running on 8000)
const openai = createOpenAI({ baseURL: 'http://localhost:8000/v1' });
// plus retry in the call
generateText({ model: openai('gpt-4o'), prompt, maxRetries: 5 });
Defensive patterns

Strategy: retry

Validate before calling

// before the call
const endpoint = new URL(baseURL);
await fetch(endpoint.origin, { method: 'HEAD', signal: AbortSignal.timeout(3000) }).catch(e => { throw new Error(`API endpoint not reachable from this host: ${e.cause?.code ?? e.message}`); });

Type guard

import { APICallError } from '@ai-sdk/provider';
function isPostConnectionError(e: unknown): e is APICallError {
  return APICallError.isInstance(e) && e.isRetryable === true && e.message.startsWith('Cannot connect to API:');
}

Try / catch

try {
  const result = await generateText({ model, prompt, maxRetries: 4 });
} catch (error) {
  if (APICallError.isInstance(error) && error.isRetryable && error.message.startsWith('Cannot connect to API:')) {
    // inspect error.cause.code: ECONNREFUSED -> service down, ETIMEDOUT -> firewall/timeout
    // escalate after exhausting retries
  }
  throw error;
}

Prevention

When it happens

Trigger: Any provider call that uses postJsonToApi/postFormDataToApi (generateText, streamText, generateObject, embeddings, etc.) when fetch itself throws: connection refused/timeout/reset (ECONNREFUSED, ETIMEDOUT, ECONNRESET, UND_ERR_SOCKET), DNS resolution failure, or body upload interrupted mid-flight.

Common situations: Wrong or unreachable baseURL (self-hosted gateways, Azure resource URL typos); API endpoint down or rate-limited at load balancer level; VPN/proxy required but not configured; container DNS failures; long uploads hitting UND_ERR_HEADERS_TIMEOUT against slow gateways; intermittent network blips in serverless environments.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/22f41ff7a54de93b. Report an issue: GitHub.