santifer/career-ops · error · Error
justjoin: careers_url or api must be a trusted justjoin.it U
Error message
justjoin: careers_url or api must be a trusted justjoin.it URL
What it means
Thrown by justjoin.fetch() at the very start of the fetch when detectUrl(entry) returns null — meaning the entry's api/careers_url is missing, empty, or failed every assertJustJoinUrl guard (invalid URL, non-HTTPS, wrong host, or wrong path). detect() uses the same detectUrl and would have returned null too, so reaching fetch() with a null detection implies the entry was forced into the justjoin provider without a valid justjoin.it URL.
Source
Thrown at providers/justjoin.mjs:110
url: `${JOB_BASE}${slug}`,
company: String(offer.companyName || '').trim(),
location: normalizeLocation(offer),
postedAt: postedAtMillis(offer.publishedAt),
};
})
.filter(Boolean);
}
/** @type {Provider} */
export default {
id: 'justjoin',
detect(entry) {
return detectUrl(entry);
},
async fetch(entry, ctx) {
if (!detectUrl(entry)) throw new Error('justjoin: careers_url or api must be a trusted justjoin.it URL');
const jobs = [];
let from = 0;
const maxPages = Number(entry.max_pages || MAX_PAGES);
for (let page = 0; page < maxPages; page++) {
const url = buildApiUrl(entry, from);
const json = await ctx.fetchJson(url, { redirect: 'error' });
const parsed = parseJustJoinResponse(json);
jobs.push(...parsed);
const next = json?.meta?.next?.cursor;
if (next == null || parsed.length === 0) break;
from = Number(next);
if (!Number.isFinite(from)) break;
}
return jobs;
},
};View on GitHub (pinned to 9b17a8ac97)
Solutions
- Set api to https://justjoin.it/api/candidate-api/offers or careers_url to a https://justjoin.it/job-offers/... URL.
- If the company is not on justjoin.it, change provider to the correct ATS.
- Remove the provider: justjoin assignment if the entry has no justjoin.it URL.
Example fix
# before — provider set but no valid URL acme: provider: justjoin name: Acme # after — provide the trusted URL acme: provider: justjoin name: Acme api: https://justjoin.it/api/candidate-api/offers
Defensive patterns
Strategy: validation
Validate before calling
import { default as justjoin } from './providers/justjoin.mjs';
// Use the provider's own detect as the source of truth:
for (const e of entries) {
if (e.provider === 'justjoin' && !justjoin.detect(e)) {
console.warn(`justjoin ${e.name}: no valid justjoin.it URL — set api or careers_url`);
}
} Type guard
/** @param {any} entry @returns {boolean} */
function justjoinEntryHasValidUrl(entry) {
const url = entry?.api || entry?.careers_url;
if (typeof url !== 'string' || !url.trim()) return false;
try {
const p = new URL(url);
return p.protocol === 'https:' && p.hostname === 'justjoin.it'
&& (p.pathname.startsWith('/job-offers') || p.pathname === '/api/candidate-api/offers');
} catch { return false; }
} Prevention
- Never set provider: justjoin without a valid https://justjoin.it URL.
- Run provider.detect() in a config dry-run to catch invalid entries pre-scan.
- If a board isn't justjoin.it, select the correct provider.
When it happens
Trigger: A portals.yml entry with provider: justjoin but no api and no careers_url; an api/careers_url that is a valid URL but not on justjoin.it (so detectUrl swallows the assertJustJoinUrl error and returns null); a non-string or whitespace-only url field.
Common situations: Forcing provider: justjoin on an entry that has no justjoin.it URL; an entry template where the url field was never filled in; an entry that points at a different board but was mislabeled justjoin.
Related errors
- justjoin: invalid URL: ${url}
- justjoin: URL must use HTTPS: ${url}
- justjoin: untrusted hostname "${parsed.hostname}" — must be
- justjoin: URL path must be /job-offers or /api/candidate-api
- lever: cannot derive API URL for ${entry.name}
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/26ae7be53d88c7eb.
Report an issue: GitHub.