santifer/career-ops · error · Error
getonbrd: ${out.length} categories configured — cap is ${MAX
Error message
getonbrd: ${out.length} categories configured — cap is ${MAX_CATEGORIES} (each one costs up to max_pages requests) What it means
resolveCategories enforces MAX_CATEGORIES because every configured category costs up to max_pages API requests per scan. Configuring more categories than the cap is rejected to protect rate limits and scan runtime.
Source
Thrown at providers/getonbrd.mjs:68
const raw = entry?.categories !== undefined ? entry.categories : entry?.category;
if (raw === undefined || raw === null) return [DEFAULT_CATEGORY];
const list = Array.isArray(raw) ? raw : [raw];
const out = [];
for (const c of list) {
if (typeof c !== 'string' || !CATEGORY_SLUG_RE.test(c.trim())) {
throw new Error(
`getonbrd: invalid category ${JSON.stringify(c)} — expected a slug like "programming" or "machine-learning-ai"`,
);
}
const slug = c.trim();
if (!out.includes(slug)) out.push(slug);
}
if (!out.length) {
throw new Error('getonbrd: `categories` is empty — omit it to use the "programming" default');
}
if (out.length > MAX_CATEGORIES) {
throw new Error(
`getonbrd: ${out.length} categories configured — cap is ${MAX_CATEGORIES} (each one costs up to max_pages requests)`,
);
}
return out;
}
/** @param {string} url */
function assertGetonbrdUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`getonbrd: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`getonbrd: URL must use HTTPS: ${url}`);
if (parsed.hostname !== TRUSTED_HOST) {
throw new Error(`getonbrd: untrusted hostname "${parsed.hostname}" — must be ${TRUSTED_HOST}`);
}View on GitHub (pinned to 1696bec4d0)
Solutions
- Trim the list to the MAX_CATEGORIES most relevant slugs (the cap value is in the message)
- Split the workload across multiple portal entries or scheduled runs
- Increase MAX_CATEGORIES in the provider only if you accept the extra request cost per category
Example fix
// before categories: ['programming', 'design', 'data-science', 'devops', 'product', 'marketing', 'sales', 'finance'] // after (cap-aware) categories: ['programming', 'data-science', 'devops']
Defensive patterns
Strategy: validation
Validate before calling
const MAX = 3; // mirror provider MAX_CATEGORIES
if ((entry.categories ?? []).length > MAX) {
entry.categories = entry.categories.slice(0, MAX);
console.warn('Trimmed getonbrd categories to cap of', MAX);
} Type guard
function isWithinCategoryCap(entry, cap) {
return !Array.isArray(entry.categories) || entry.categories.length <= cap;
} Try / catch
try {
const jobs = await getonbrdProvider.fetch(entry, ctx);
} catch (e) {
if (/getonbrd: \d+ categories configured/.test(String(e.message))) {
console.warn('Too many categories for', entry.name, '— reduce to the cap and rescan');
return [];
}
throw e;
} Prevention
- Prioritize the few highest-value categories per portal entry instead of listing many
- Spread broad coverage across multiple scheduled entries/runs
- Check the provider's MAX_CATEGORIES before generating config programmatically
When it happens
Trigger: A portal entry listing more than MAX_CATEGORIES valid, deduplicated slugs — e.g. copying the full getonbrd category index into one entry.
Common situations: Users trying to scan 'everything' at once; merging configs from multiple sources that concatenate category lists; forgetting dedup happens before the check (duplicates don't save you).
Related errors
- gmail: invalid days_back "${ctx?.settings?.days_back}" (must
- ratePerMin must be a finite number > 0, got ${ratePerMin}
- capacity must be a finite number >= 1, got ${capacity}
- arbeitsagentur: entry "${entry.name || '(unnamed)'}" has no
- ashby: invalid URL: ${url}
AI-assisted analysis of santifer/career-ops@1696bec4d0 (2026-09-01).
Data as JSON: /api/errors/d8c711e0b2bc0687.
Report an issue: GitHub.