santifer/career-ops · error · Error

jobstreet: invalid URL: ${url}

Error message

jobstreet: invalid URL: ${url}

What it means

Thrown by assertJobstreetUrl when new URL(url) throws — the supplied api URL is not a parseable absolute URL. Unlike the himalayas/jobspresso guards, the jobstreet assert runs against entry.api || DEFAULT_API, so it IS reachable from the public contract whenever entry.api is set to a malformed string.

Source

Thrown at providers/jobstreet.mjs:56

  'jobstreet.co.id',
  'sg.jobstreet.com',
  'my.jobstreet.com',
  'www.seek.com.au',
  'www.seek.co.nz',
]);

// v5 API paths (the client-side JS on jobstreet uses these relative paths
// resolved against the current origin). We keep the allowlist for SSRF
// protection on the base URL, then build the v5 search path from it.
const V5_SEARCH_PATH = '/api/jobsearch/v5/search';

/** @param {string} url */
function assertJobstreetUrl(url) {
  let parsed;
  try {
    parsed = new URL(url);
  } catch {
    throw new Error(`jobstreet: invalid URL: ${url}`);
  }
  if (parsed.protocol !== 'https:') throw new Error(`jobstreet: URL must use HTTPS: ${url}`);
  if (!ALLOWED_JOBSTREET_HOSTS.has(parsed.hostname))
    throw new Error(`jobstreet: untrusted hostname "${parsed.hostname}" — must be one of: ${[...ALLOWED_JOBSTREET_HOSTS].join(', ')}`);
  return url;
}

/**
 * Derive the origin from the API hostname.
 * e.g. id.jobstreet.com → https://id.jobstreet.com
 * @param {string} apiUrl
 * @returns {string}
 */
function deriveOrigin(apiUrl) {
  try {
    const parsed = new URL(apiUrl);
    return `${parsed.protocol}//${parsed.hostname}`;
  } catch {

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Set api: to a full absolute URL including the https:// scheme, e.g. https://id.jobstreet.com/api/jobsearch/v5/search.
  2. If you do not need a custom endpoint, remove api: and let the provider use DEFAULT_API.
  3. Trim whitespace and confirm new URL(entry.api) does not throw before running the scan.

Example fix

# before
- name: Jobstreet ID
  provider: jobstreet
  api: id.jobstreet.com/api/jobsearch/v5/search

# after
- name: Jobstreet ID
  provider: jobstreet
  api: https://id.jobstreet.com/api/jobsearch/v5/search
Defensive patterns

Strategy: validation

Validate before calling

// Validate a user-supplied entry.api before the provider's assert throws.
if (typeof entry.api === 'string') {
  try { new URL(entry.api); }
  catch { throw new Error(`jobstreet: entry.api is not a valid absolute URL: ${entry.api}`); }
}

Type guard

/** True for a parseable absolute URL string. */
function isAbsoluteUrl(value) {
  if (typeof value !== 'string' || !value.trim()) return false;
  try { new URL(value); return true; } catch { return false; }
}

Try / catch

try {
  return await jobstreetProvider.fetch(entry, ctx);
} catch (err) {
  if (/jobstreet: invalid URL/.test(err.message)) {
    console.error(`config: ${entry.name} — entry.api is malformed: ${err.message}`);
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: A portal entry with provider: jobstreet and api: set to a malformed string — missing scheme (e.g. 'id.jobstreet.com/api/jobsearch/v5/search'), stray whitespace/characters, or a relative path. When entry.api is absent the provider uses the well-formed DEFAULT_API and this never fires.

Common situations: Omitting the https:// scheme when setting api:; a copy-paste that included surrounding quotes or whitespace; a templating step that produced a relative URL; YAML treating a value with special characters oddly.

Related errors


AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13). Data as JSON: /api/errors/bf6bdebc2c61dd9f. Report an issue: GitHub.