santifer/career-ops · error · Error
H1B_API_BASE must not contain a query string or a fragment.
Error message
H1B_API_BASE must not contain a query string or a fragment.
What it means
resolveBase() rejects an H1B_API_BASE containing a query string (?) or fragment (#). Paths are appended to the base as `${base}/employers/...`, so a query or fragment would swallow the appended path — the request would hit the base URL itself and return data about the wrong (or no) company.
Source
Thrown at plugins/h1b-sponsor/lib/api.mjs:60
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);
const allowedScheme = parsed.protocol === 'https:' || (parsed.protocol === 'http:' && loopback);
if (!allowedScheme) {
throw new Error(`H1B_API_BASE must use https, or http on loopback: ${trimmed}`);
}
// Appended as `${base}/employers/...`, so a trailing slash would double up.
return trimmed.replace(/\/+$/, '');
}
const USER_AGENT = 'career-ops-plugin-h1b-sponsor/1.0';
const DEFAULT_TIMEOUT_MS = 10_000;
const MAX_RETRY_WAIT_MS = 10_000;View on GitHub (pinned to 1696bec4d0)
Solutions
- Strip everything from the '?' onward: keep only scheme, host, and path prefix in H1B_API_BASE.
- If the API requires a key as a query parameter, use a proxy that appends it, or a base path that encodes it, not the base URL.
- Verify with node: `const u = new URL(v); u.search || u.hash` must both be empty.
Example fix
// before (.env) H1B_API_BASE=https://api.example.com/v1?apikey=xyz // after H1B_API_BASE=https://api.example.com/v1
Defensive patterns
Strategy: validation
Validate before calling
function baseHasQueryOrFragment(v) {
try { const u = new URL(v); return Boolean(u.search || u.hash); } catch { return false; }
}
// guard: if (baseHasQueryOrFragment(process.env.H1B_API_BASE)) strip or fix it; Type guard
function isCleanBaseUrl(v) {
try { const u = new URL(v); return !u.search && !u.hash; } catch { return false; }
} Try / catch
try {
const data = await lookupEmployer(name);
} catch (e) {
if (e.message.includes('must not contain a query string or a fragment')) {
console.error('H1B_API_BASE must be scheme+host+path only; move any api key out of the URL.');
return;
}
throw e;
} Prevention
- Strip tracking params and #anchors when copying a URL into config.
- Remember the base is a prefix: paths like /employers/... are appended, so '?' or '#' would swallow them.
- Normalize the value once at startup: new URL(v) then rebuild without search/hash (or reject).
- Never try to pass API keys as query params in the base URL.
When it happens
Trigger: Setting H1B_API_BASE to a URL like https://api.example.com?key=abc or https://example.com/page#section and calling any function that constructs `${apiBase()}/employers/...`.
Common situations: Pasting a full page URL from a browser (which carries ?utm_... or # anchors) into the config; trying to pass an API key as a query parameter in the base URL.
Related errors
- H1B_API_BASE is not a valid URL: ${trimmed}
- APIFY_TOKEN not set — enable apify in config/plugins.yml and
- gmail: missing GMAIL_CLIENT_ID / GMAIL_CLIENT_SECRET / GMAIL
- H1B_API_BASE is set but empty. Unset it to use the default e
- H1B_API_BASE must not embed credentials.
AI-assisted analysis of santifer/career-ops@1696bec4d0 (2026-09-01).
Data as JSON: /api/errors/53415f1ca5a8e428.
Report an issue: GitHub.