santifer/career-ops · error · Error

itviec: invalid URL

Error message

itviec: invalid URL: ${url}

What it means

assertItviecUrl parses a URL and throws this error when new URL() fails, i.e. the string is not an absolute, well-formed URL. The itviec provider runs this check before every request so malformed config can never reach the fetch layer.

Solutions

  1. Set the URL to a full absolute https URL, e.g. https://www.itviec.com/it-jobs
  2. Trim/strip surrounding whitespace and quotes from the config value
  3. Validate all careers_url values in portals.yml are absolute URLs before running scan.mjs
  4. If the value comes from an env var or CLI arg, check it is defined and well-formed before passing it in

Example fix

// before
assertItviecUrl('itviec.com/it-jobs');
// after
assertItviecUrl('https://www.itviec.com/it-jobs');
Defensive patterns

Strategy: validation

Validate before calling

function isValidAbsoluteUrl(url) {
  if (typeof url !== 'string') return false;
  try { new URL(url.trim()); return true; } catch { return false; }
}
// pre-validate config: if (!isValidAbsoluteUrl(entry.careers_url)) skip;

Type guard

const isUrl = (v) => { try { return typeof v === 'string' && !!new URL(v); } catch { return false; } };

Try / catch

try {
  assertItviecUrl(url);
} catch (err) {
  if (/invalid URL/.test(err.message)) {
    console.warn(`itviec entry has malformed URL, skipping: ${url}`);
    return null;
  }
  throw err;
}

Prevention

When it happens

Trigger: new URL(url) throws for the given string — relative path like '/it-jobs', missing scheme ('itviec.com/it-jobs'), stray whitespace, or a non-string coerced to garbage — and it is passed to assertItviecUrl.

Common situations: portals.yml careers_url written without https://; a template placeholder left unsubstituted; the entry stores a path instead of a full URL; trailing spaces/quotes around the value in YAML.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16). Data as JSON: /api/errors/cd2da10f94172377. Report an issue: GitHub.

Appendix: source

Thrown at providers/itviec.mjs:82

const LOCATION_RE = /#map-pin"?><\/use><\/svg>\s*<div[^>]*title=["']([^"']*)["']/i;

/** Relative publication label: English "Posted … ago" or Vietnamese "Đăng … trước". */
const POSTED_LABEL_RE =
  /(?:Posted|Đăng)\s*:?\s*(?:<\/\w+>\s*)?([^.<]{0,40}?(?:ago|trước)|today|hôm nay)/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 assertItviecUrl(url) {
  let parsed;
  try {
    parsed = new URL(url);
  } catch {
    throw new Error(`itviec: invalid URL: ${url}`);
  }
  if (parsed.protocol !== 'https:') throw new Error(`itviec: URL must use HTTPS: ${url}`);
  if (parsed.hostname !== TRUSTED_HOST) {
    throw new Error(`itviec: untrusted hostname "${parsed.hostname}" — must be ${TRUSTED_HOST}`);
  }
  return url;
}

/**
 * Collapse a markup fragment to its visible text.
 * @param {string} fragment
 * @returns {string}
 */
export function visibleText(fragment) {
  return decodeEntities(
    String(fragment ?? '')
      .replace(/<!--[\s\S]*?-->/g, ' ')
      .replace(/<[^>]+>/g, ' '),

View on GitHub (pinned to aac998c7ed)