santifer/career-ops · error · Error
senjob: invalid URL: ${url}
Error message
senjob: invalid URL: ${url} What it means
assertSenjobUrl parses its argument with new URL(); malformed strings throw SyntaxError, which is caught and rethrown as this error prefixed with the senjob provider tag. It runs before every listing-page fetch, guaranteeing the provider never requests an unparseable URL.
Source
Thrown at providers/senjob.mjs:77
const POSTING_ANCHOR_RE =
/<a\s[^>]*href="https:\/\/senjob\.com\/jobseekers\/[^"]*?_e_\d+\.html"[^>]*>([\s\S]*?)<\/a>/i;
/** The machine-readable publication date, hidden next to its localized form. */
const HIDDEN_ISO_DATE_RE = /display:\s*none;?\s*"?>\s*(\d{4}-\d{2}-\d{2})\s*</i;
/** @param {any} ctx @param {number} ms */
function sleep(ctx, ms) {
if (typeof ctx?.sleep === 'function') return ctx.sleep(ms);
return new Promise((r) => setTimeout(r, ms));
}
/** @param {string} url */
function assertSenjobUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`senjob: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`senjob: URL must use HTTPS: ${url}`);
if (parsed.hostname !== TRUSTED_HOST) {
throw new Error(`senjob: untrusted hostname "${parsed.hostname}" — must be ${TRUSTED_HOST}`);
}
return url;
}
/**
* Collapse a markup fragment to its visible text.
* Comments are stripped FIRST: the anchor bodies carry `<!-- d ico postulez -->`
* between the title and a spacer image, and a naive tag strip would leave the
* comment body sitting inside the title.
* @param {string} fragment
* @returns {string}
*/
export function visibleText(fragment) {
return decodeEntities(View on GitHub (pinned to 1696bec4d0)
Solutions
- Pass only URLs built by buildListUrl(page), which always yields the absolute https://senjob.com/offres-d-emploi.php form
- If calling directly, ensure the input is a fully-qualified absolute URL including the https:// scheme
- Trim/normalize any user- or config-supplied string before validation
Example fix
// before assertSenjobUrl(entry.careers_url ?? 'senjob.com/offres-d-emploi.php'); // after assertSenjobUrl(buildListUrl(1)); // https://senjob.com/offres-d-emploi.php
Defensive patterns
Strategy: validation
Validate before calling
function isValidAbsoluteUrl(url) {
try { new URL(url); return true; } catch { return false; }
}
if (!isValidAbsoluteUrl(candidate)) throw new Error(`senjob: not an absolute URL: ${candidate}`); Type guard
function isValidAbsoluteUrl(url) {
try { new URL(url); return typeof url === 'string' && url.length > 0; } catch { return false; }
} Try / catch
try {
assertSenjobUrl(url);
} catch (err) {
if (String(err.message).startsWith('senjob: invalid URL')) {
console.error(`Rejected malformed URL: ${err.message}`);
return null;
}
throw err;
} Prevention
- Build senjob URLs exclusively with buildListUrl(page) — the constant LIST_URL is always well-formed
- Trim config/env strings before passing them into URL construction
- Add a smoke test asserting buildListUrl output parses for pages 1..N
- If extending the provider, keep URL construction and validation adjacent so malformed input cannot slip in
When it happens
Trigger: A string reaching the assertion that new URL() rejects: empty string, missing scheme ('senjob.com/offres-d-emploi.php'), whitespace/newlines, or a corrupted buildListUrl result. With the fixed LIST_URL constant this is only reachable via direct calls or edits to buildListUrl/entry-driven URL construction.
Common situations: Calling assertSenjobUrl from custom tooling with a configured (unvalidated) URL; someone changing LIST_URL to a relative path or templated placeholder; string concatenation injecting spaces.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- H1B_API_BASE is not a valid URL: ${trimmed}
- H1B_API_BASE must not embed credentials.
- H1B_API_BASE must not contain a query string or a fragment.
- H1B_API_BASE must use https, or http on loopback: ${trimmed}
- bamboohr: untrusted hostname "${parsed.hostname}" — must mat
AI-assisted analysis of santifer/career-ops@1696bec4d0 (2026-09-01).
Data as JSON: /api/errors/2f4fe4d45b4f3e58.
Report an issue: GitHub.