santifer/career-ops · error · Error

careerviet: URL must use HTTPS: ${url}

Error message

careerviet: URL must use HTTPS: ${url}

What it means

The CareerViet provider enforces HTTPS on every request URL. When assertCareerVietUrl parses the URL but parsed.protocol is not 'https:', it throws this error. The provider scrapes server-rendered search pages over plain HTTPS; allowing http would silently downgrade transport and contradict the fixed-host security posture (only https://careerviet.vn is ever requested).

Source

Thrown at providers/careerviet.mjs:108

 * apart; both wrap their <time> the same way.
 */
const UPDATED_DATE_RE = /Cập nhật(?:<!--[\s\S]*?-->)?\s*:?\s*(?:<\/span>)?\s*<time>([\d/-]+)<\/time>/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 assertCareerVietUrl(url) {
  let parsed;
  try {
    parsed = new URL(url);
  } catch {
    throw new Error(`careerviet: invalid URL: ${url}`);
  }
  if (parsed.protocol !== 'https:') throw new Error(`careerviet: URL must use HTTPS: ${url}`);
  if (parsed.hostname !== TRUSTED_HOST) {
    throw new Error(`careerviet: 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, ' '),
  )
    .replace(/\s+/g, ' ')

View on GitHub (pinned to 1696bec4d0)

Solutions

  1. Change the configured URL scheme to https://
  2. If the URL is built dynamically, use an https base: new URL(path, 'https://careerviet.vn')
  3. Remove any middleware/proxy that downgrades https to http for these requests
  4. Pre-validate with new URL(u).protocol === 'https:' before passing URLs into the provider

Example fix

// before
const url = `http://careerviet.vn/viec-lam?page=${page}`;
// after
const url = `https://careerviet.vn/viec-lam?page=${page}`;
Defensive patterns

Strategy: validation

Validate before calling

function isHttpsUrl(value) {
  if (typeof value !== 'string') return false;
  try { return new URL(value).protocol === 'https:'; } catch { return false; }
}
if (!isHttpsUrl(entry.careers_url)) entry.careers_url = entry.careers_url.replace(/^http:/, 'https:');

Type guard

function isHttpsCareervietUrl(value) {
  if (typeof value !== 'string') return false;
  try {
    const p = new URL(value);
    return p.protocol === 'https:' && p.hostname === 'careerviet.vn';
  } catch { return false; }
}

Try / catch

try {
  await provider.fetch(entry, ctx);
} catch (err) {
  if (String(err.message).includes('must use HTTPS')) {
    console.error(`${entry.name}: careerviet URLs must start with https://`);
  } else throw err;
}

Prevention

When it happens

Trigger: An entry or direct call supplying http://careerviet.vn/...; code that builds the URL from an http base constant; a proxy or test harness rewriting the scheme; calling assertCareerVietUrl on a constructed page URL where the base was http.

Common situations: Legacy config predating an HTTPS-only policy; developer testing against a local http mock of the board; URL copied from an insecure mirror or cached http link.

Related errors


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