santifer/career-ops · error · Error

H1B_API_BASE is not a valid URL: ${trimmed}

Error message

H1B_API_BASE is not a valid URL: ${trimmed}

What it means

resolveBase() validates the H1B_API_BASE environment variable before any request is made. The value failed `new URL(trimmed)`, meaning it is not a syntactically valid absolute URL (missing scheme, spaces, typos like 'h1b.example.com/api' without protocol). The library throws early with a named configuration error instead of letting fetch fail opaquely later.

Source

Thrown at plugins/h1b-sponsor/lib/api.mjs:50

}

function resolveBase() {
  const raw = process.env.H1B_API_BASE;
  // Absent means "use the default". Present but blank is a misconfiguration
  // (an unset shell variable, an empty .env line, a CI secret that did not
  // populate), and silently falling back would send someone's shortlist and
  // their token to a host they believed they had replaced.
  if (raw === undefined) return DEFAULT_BASE;
  const trimmed = String(raw).trim();
  if (!trimmed) {
    throw new Error('H1B_API_BASE is set but empty. Unset it to use the default endpoint.');
  }

  let parsed;
  try {
    parsed = new URL(trimmed);
  } catch {
    throw new Error(`H1B_API_BASE is not a valid URL: ${trimmed}`);
  }
  if (parsed.username || parsed.password) {
    // Undici refuses a credentialed Request anyway, and the value reaches
    // stdout through the source field, so this would print a password.
    throw new Error('H1B_API_BASE must not embed credentials.');
  }
  if (parsed.search || parsed.hash) {
    // Paths are appended, so a query or fragment swallows them: the request
    // would go to the base itself and answer about a company never asked for.
    throw new Error('H1B_API_BASE must not contain a query string or a fragment.');
  }
  // Plain http would put an Authorization header on the wire in the clear.
  // Loopback is exempt so a self-hoster can develop against a local worker,
  // but only for http. Exempting every scheme on a loopback host let
  // ftp://localhost and ws://localhost past validation, and those die later
  // inside fetch as a bare "fetch failed", which is the opaque failure this
  // check exists to replace with a named configuration error.
  const loopback = /^(localhost|127\.\d+\.\d+\.\d+|\[::1\]|::1)$/i.test(parsed.hostname);

View on GitHub (pinned to 1696bec4d0)

Solutions

  1. Prefix the value with a full scheme, e.g. H1B_API_BASE=https://h1b.example.com in .env or the environment.
  2. Check for stray characters: surrounding quotes, spaces, or a single slash after the scheme; fix and re-run.
  3. If you meant to use the plugin's default API, unset H1B_API_BASE entirely instead of setting it to a partial value.
  4. Validate locally before running: `new URL(process.env.H1B_API_BASE)` in node should not throw.

Example fix

// before (.env)
H1B_API_BASE=h1b-api.example.com/v1
// after
H1B_API_BASE=https://h1b-api.example.com/v1
Defensive patterns

Strategy: validation

Validate before calling

function isValidApiBase(v) {
  if (typeof v !== 'string' || !v.trim()) return false;
  try { new URL(v.trim()); return true; } catch { return false; }
}
// before running: if (!isValidApiBase(process.env.H1B_API_BASE)) fix config;

Type guard

function isHttpUrl(v) {
  try { const u = new URL(v); return u.protocol === 'https:' || u.protocol === 'http:'; }
  catch { return false; }
}

Try / catch

try {
  const profile = await getEmployerProfile(id);
} catch (e) {
  if (e.message.startsWith('H1B_API_BASE is not a valid URL')) {
    console.error('Fix H1B_API_BASE in .env — must be a full absolute URL, e.g. https://host');
    process.exitCode = 2;
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling any API function (e.g. getEmployerProfile) when the H1B_API_BASE env var is set to a string that the URL constructor cannot parse — missing 'https://' scheme, containing spaces or invalid characters, or being a bare hostname/path.

Common situations: Copying an API host without the scheme into .env; wrapping the value in shell quotes that leak into the variable; typos like 'https:/example.com' (single slash); using a relative path like '/api' by mistake.

Related errors


AI-assisted analysis of santifer/career-ops@1696bec4d0 (2026-09-01). Data as JSON: /api/errors/c0cd18473b2098c3. Report an issue: GitHub.