santifer/career-ops · error · Error
justjoin: invalid URL: ${url}
Error message
justjoin: invalid URL: ${url} What it means
Thrown by assertJustJoinUrl() when new URL(url) throws — the input is not a parseable URL at all (empty, malformed, missing scheme, unbalanced brackets). This is the first guard in the justjoin.it URL validator; it precedes the protocol, hostname, and path checks. The validator is the single chokepoint for both detect() and buildApiUrl().
Source
Thrown at providers/justjoin.mjs:19
// @ts-check
/** @typedef {import('./_types.js').Provider} Provider */
// JustJoin.it provider — hits the current candidate offers API.
// Browser URLs under https://justjoin.it/job-offers/... are accepted for
// detection, but fetches use https://justjoin.it/api/candidate-api/offers.
const ALLOWED_HOSTS = new Set(['justjoin.it']);
const API_BASE = 'https://justjoin.it/api/candidate-api/offers';
const JOB_BASE = 'https://justjoin.it/job-offer/';
const PAGE_SIZE = 100;
const MAX_PAGES = 50;
function assertJustJoinUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`justjoin: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`justjoin: URL must use HTTPS: ${url}`);
if (!ALLOWED_HOSTS.has(parsed.hostname)) {
throw new Error(`justjoin: untrusted hostname "${parsed.hostname}" — must be justjoin.it`);
}
if (!parsed.pathname.startsWith('/job-offers') && parsed.pathname !== '/api/candidate-api/offers') {
throw new Error(`justjoin: URL path must be /job-offers or /api/candidate-api/offers: ${url}`);
}
return parsed;
}
function detectUrl(entry) {
const url = entry.api || entry.careers_url || '';
if (typeof url !== 'string' || !url.trim()) return null;
try {
const parsed = assertJustJoinUrl(url);
return { url: parsed.href };
} catch {View on GitHub (pinned to 9b17a8ac97)
Solutions
- Set api or careers_url to a full https://justjoin.it/... URL.
- Check the YAML entry for missing quotes or an empty value.
- Verify the field is a non-empty string before it reaches the validator.
Example fix
# before acme: provider: justjoin api: justjoin.it/api/candidate-api/offers # after acme: provider: justjoin api: https://justjoin.it/api/candidate-api/offers
Defensive patterns
Strategy: validation
Validate before calling
function isParseableUrl(url) {
try { new URL(url); return true; } catch { return false; }
}
// before scan:
for (const e of justjoinEntries) {
const u = e.api || e.careers_url;
if (typeof u !== 'string' || !u.trim() || !isParseableUrl(u)) {
console.warn(`justjoin ${e.name}: api/careers_url is missing or unparseable`);
}
} Type guard
/** @param {string} url @returns {boolean} */
function isParseableHttpsUrl(url) {
try { new URL(url); return true; } catch { return false; }
} Prevention
- Require a full https:// URL in the api/careers_url field for every justjoin entry.
- Lint config entries for empty or scheme-less URLs before scanning.
- Quote YAML string values to avoid type-coercion surprises.
When it happens
Trigger: An api or careers_url field that is empty, contains whitespace only, lacks a scheme (e.g. 'justjoin.it/job-offers'), or contains characters that break the URL parser (spaces, stray brackets).
Common situations: A portals.yml entry with a blank or commented-out url; a copy-paste that lost the https:// prefix; a YAML quoting issue that produced an unexpected type.
Related errors
- justjoin: URL must use HTTPS: ${url}
- flowxtra: untrusted hostname "${parsed.hostname}" — must be
- gem: invalid URL: ${url}
- gem: URL must use HTTPS: ${url}
- gem: untrusted hostname "${parsed.hostname}" — must be one o
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/4528aff245591b42.
Report an issue: GitHub.