santifer/career-ops · error · Error

4dayweek: invalid URL: ${url}

Error message

4dayweek: invalid URL: ${url}

What it means

assertFourDayUrl() in providers/4dayweek.mjs is an SSRF/allowlist guard: before the provider fetches or links any URL, it parses it with new URL() and throws 'invalid URL' if parsing fails. This catches malformed strings — missing scheme, spaces, typos — before they reach fetch.

Source

Thrown at providers/4dayweek.mjs:53

    try {
      const parsed = new URL(value);
      if (parsed.protocol === 'https:' && parsed.hostname === TRUSTED_HOST) {
        return { url: FEED_BASE };
      }
    } catch {
      // Ignore malformed URLs; another provider may still claim the entry.
    }
  }
  return null;
}

/** @param {string} url */
function assertFourDayUrl(url) {
  let parsed;
  try {
    parsed = new URL(url);
  } catch {
    throw new Error(`4dayweek: invalid URL: ${url}`);
  }
  if (parsed.protocol !== 'https:') throw new Error(`4dayweek: URL must use HTTPS: ${url}`);
  if (parsed.hostname !== TRUSTED_HOST) {
    throw new Error(`4dayweek: untrusted hostname "${parsed.hostname}" — must be ${TRUSTED_HOST}`);
  }
  return url;
}

/** Resolve the page cap: a positive integer `max_pages` on the entry, capped. */
function resolveMaxPages(entry) {
  const v = entry?.max_pages;
  if (Number.isInteger(v) && v > 0) return Math.min(v, MAX_PAGES_CAP);
  return DEFAULT_MAX_PAGES;
}

// NaN-safe: posted is epoch SECONDS → ms; anything non-finite yields undefined.
function toEpochMs(seconds) {
  return Number.isFinite(seconds) ? seconds * 1000 : undefined;

View on GitHub (pinned to 1696bec4d0)

Solutions

  1. Print/log the exact url value at the call site — the message already interpolates it — and look for undefined/empty/trailing whitespace.
  2. Fix the source entry (portals.yml, feed config) so it is an absolute URL starting with https://4dayweek.io/...
  3. If the URL comes from user input, trim() it and validate with new URL() before calling the provider.
  4. Ensure the entry's URL field actually exists (not undefined) — a missing field coerces to the string 'undefined'.

Example fix

// before
provider.check('4dayweek.io/job/123'); // TypeError: invalid URL
// after
provider.check('https://4dayweek.io/job/123');
Defensive patterns

Strategy: validation

Validate before calling

function isValidUrl(url) {
  if (typeof url !== 'string') return false;
  try { new URL(url); return true; } catch { return false; }
}
if (!isValidUrl(entry.url)) throw new Error(`Skip entry: malformed url ${JSON.stringify(entry.url)}`);

Type guard

function isUrlString(v) {
  if (typeof v !== 'string' || v.length === 0) return false;
  try { new URL(v); return true; } catch { return false; }
}

Try / catch

try {
  provider.check(url);
} catch (err) {
  if (err.message.startsWith('4dayweek: invalid URL')) {
    console.warn(`Skipping malformed entry: ${err.message}`);
    return null;
  }
  throw err;
}

Prevention

When it happens

Trigger: Passing any string that new URL() rejects to the 4dayweek provider's URL assertion path: an empty string, a bare hostname like '4dayweek.io/job/123', a URL with unencoded spaces, or a config entry where the URL field is undefined/null coerced to 'undefined'.

Common situations: portals.yml or a feed entry missing the url field (undefined interpolated into the message); copy-pasted URLs containing trailing whitespace or surrounding quotes; hand-written URLs missing 'https://'; template strings where an upstream variable was empty.

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@1696bec4d0 (2026-09-01). Data as JSON: /api/errors/e035c37079e0b31a. Report an issue: GitHub.