jackwener/OpenCLI · critical · CommandExecutionError

${label} request failed: ${err.message}

Error message

${label} request failed: ${err.message}

What it means

This CommandExecutionError wraps a low-level fetch failure when the HTTP request to wttr.in never completes — the fetch call itself rejected (DNS failure, connection refused/reset, timeout, TLS error). The label ('wttr forecast', etc.) is prefixed and the underlying err.message is appended for diagnosis.

Source

Thrown at clis/wttr/utils.js:25

export const WTTR_BASE = 'https://wttr.in';
const UA = 'opencli-wttr/1.0';

export function requireString(value, name) {
    if (typeof value !== 'string' || !value.trim()) {
        throw new ArgumentError(`--${name} is required`);
    }
    return value.trim();
}

export async function wttrFetch(location, label) {
    // wttr.in path-encodes the location. Spaces → %20 is fine; commas survive.
    const url = `${WTTR_BASE}/${encodeURIComponent(location)}?format=j1`;
    let resp;
    try {
        resp = await fetch(url, { headers: { 'User-Agent': UA, accept: 'application/json' } });
    } catch (err) {
        throw new CommandExecutionError(`${label} request failed: ${err.message}`);
    }
    if (resp.status === 404) {
        throw new EmptyResultError(label, `${label} could not find location "${location}".`);
    }
    if (!resp.ok) {
        throw new CommandExecutionError(`${label} returned HTTP ${resp.status}.`);
    }
    let body;
    try {
        body = await resp.json();
    } catch (err) {
        // wttr.in falls back to plain-text "Unknown location" for some bad inputs;
        // promote that to EmptyResult instead of pretending we got JSON.
        throw new EmptyResultError(label, `${label} returned non-JSON body (likely unknown location).`);
    }
    return body;
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify network connectivity and DNS for wttr.in (curl -v 'https://wttr.in/Paris?format=j1')
  2. Configure proxy environment variables (HTTPS_PROXY) if behind a proxy
  3. Retry with backoff for transient connection issues
  4. Set up a fallback weather source (e.g. NWS for US locations)

Example fix

// before
const body = await wttrFetch(location, 'wttr forecast'); // throws offline
// after
try {
  const body = await wttrFetch(location, 'wttr forecast');
} catch (err) {
  if (err instanceof CommandExecutionError) body = await fallbackFetch(location);
  else throw err;
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight connectivity check
try {
  await fetch('https://wttr.in/?format=j1', { method: 'HEAD' });
} catch {
  throw new Error('wttr.in is unreachable; check network/proxy');
}

Try / catch

try {
  result = await forecast({ location });
} catch (err) {
  if (err instanceof CommandExecutionError && err.message.includes('request failed')) {
    // transient network issue: retry with backoff
    result = await withRetry(() => forecast({ location }), 3);
  } else throw err;
}

Prevention

When it happens

Trigger: wttrFetch calls fetch(`https://wttr.in/${encodeURIComponent(location)}?format=j1`) and the promise rejects before a response object exists.

Common situations: Being offline or behind a blocking corporate proxy; DNS resolution failure; firewall blocking wttr.in; Node without network access in CI; TLS interception.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/e1d8d02fc9223d83. Report an issue: GitHub.