usebruno/bruno · error · Error

Failed to fetch PAC (${err.response.status})

Error message

Failed to fetch PAC (${err.response.status})

What it means

Thrown by downloadPac when axios.get(pacSource) completes with an HTTP response (err.response is defined) whose status is not 2xx. It distinguishes an HTTP-level failure of the PAC host from a transport-level failure (DNS, timeout, connection refused) which is re-thrown unchanged. The status code is embedded so the caller can decide whether to retry, fall back, or surface to the user.

Source

Thrown at packages/bruno-requests/src/utils/pac-resolver.ts:62

    proxy: false,
    responseType: 'text',
    maxRedirects: 3
  };

  if (pacSource.startsWith('https://')) {
    const agentOpts: AgentOptions = {
      ca: tlsOptions.ca,
      rejectUnauthorized: tlsOptions.rejectUnauthorized,
      minVersion: tlsOptions.minVersion as AgentOptions['minVersion']
    };
    config.httpsAgent = new https.Agent(agentOpts);
  }

  try {
    const response = await axios.get(pacSource, config);
    return response.data;
  } catch (err: any) {
    if (err.response) throw new Error(`Failed to fetch PAC (${err.response.status})`);
    throw err;
  }
}

export type GetPacResolverParams = {
  pacSource: string;
  httpsAgentRequestFields?: TlsOptions;
  opts?: { cacheTtlMs?: number; timeoutMs?: number };
};

export async function getPacResolver({ pacSource, httpsAgentRequestFields = {}, opts = {} }: GetPacResolverParams): Promise<PacWrapper> {
  if (!pacSource) throw new Error('pacSource must be provided');

  const cacheTtlMs = opts.cacheTtlMs ?? 5 * 60 * 1000;
  let key: string;
  if (pacSource.startsWith('https://')) {
    const caRaw = httpsAgentRequestFields.ca;
    const caHash = caRaw

View on GitHub (pinned to 9bdd81c7bd)

Solutions

  1. Verify the PAC URL by opening it in a browser or with curl -i; expect a 200 with JavaScript content.
  2. If 401/403: provide the required auth (the library disables axios proxy with proxy:false, so authenticating to an upstream proxy is not supported — host the PAC on an unauthenticated endpoint instead).
  3. If 502/503: treat as transient and retry with backoff, or fall back to direct connection and warn the user.
  4. If 404: correct the configured pac_url in the collection/system proxy settings.

Example fix

// before
const pac = await getPacResolver({ pacSource: 'https://corp/proxy.pac' });

// after
let pac;
try {
  pac = await getPacResolver({ pacSource: 'https://corp/proxy.pac' });
} catch (e) {
  if (/Failed to fetch PAC \(5\d{2}\)/.test(e.message)) {
    // gateway hiccup — retry once, then degrade to direct
    pac = await getPacResolver({ pacSource: 'https://corp/proxy.pac' }).catch(() => null);
  } else throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

async function pacReachable(url, { timeoutMs = 3000 } = {}) {
  try {
    const res = await fetch(url, { method: 'GET', signal: AbortSignal.timeout(timeoutMs) });
    if (!res.ok) return { ok: false, status: res.status };
    const text = await res.text();
    return { ok: /function\s+FindProxyForURL/i.test(text), status: res.status, text };
  } catch (e) { return { ok: false, status: 0, error: e }; }
}
const probe = await pacReachable(pacSource);
if (!probe.ok) throw new Error(`PAC not usable (${probe.status})`);

Type guard

function isPacFetchError(e) {
  return e instanceof Error && /^Failed to fetch PAC \(\d+\)$/.test(e.message);
}
function pacStatusFromError(e) {
  const m = e?.message?.match(/Failed to fetch PAC \((\d+)\)/);
  return m ? Number(m[1]) : null;
}

Try / catch

let pac;
try {
  pac = await getPacResolver({ pacSource, httpsAgentRequestFields, opts });
} catch (e) {
  const status = pacStatusFromError(e);
  if (status && status >= 500 && attemptsLeft > 0) {
    await delay(500); return getPacResolverWithRetry(...); // retry 5xx once
  }
  if (status === 404 || status === 401 || status === 403) {
    // non-transient — degrade to direct and warn
    pac = null;
  } else throw e;
}

Prevention

When it happens

Trigger: getPacResolver/downloadPac is called with a pacSource pointing to a PAC URL that returns 401/403 (auth required), 404 (wrong URL), 500/502/503 (proxy host down or misconfigured gateway), or any other non-2xx. The catch only fires when err.response exists; pure network errors propagate as the original axios error.

Common situations: Corporate PAC URL changed and the configured value is now stale (404); PAC host sits behind SSO/auth that rejects unauthenticated requests (401/403); the PAC-serving reverse proxy is temporarily down (502/503); typo in the URL; PAC endpoint moved off the default port.

Related errors


AI-assisted analysis of usebruno/bruno@9bdd81c7bd (2026-08-13). Data as JSON: /api/errors/08e04d64de106678. Report an issue: GitHub.