santifer/career-ops · error · Error
getonbrd: invalid category ${JSON.stringify(c)} — expected a
Error message
getonbrd: invalid category ${JSON.stringify(c)} — expected a slug like "programming" or "machine-learning-ai" What it means
getonbrd's resolveCategories validates each configured category against CATEGORY_SLUG_RE (lowercase kebab-case slugs). Non-string values or strings that are not valid slugs are rejected with an example of the expected format, preventing malformed API requests.
Source
Thrown at providers/getonbrd.mjs:57
/**
* Resolve the categories to scan, in config order, deduped.
*
* `categories:` (array) wins over `category:` (string); neither → the
* `programming` default, which keeps pre-existing entries byte-identical.
* Exported for tests.
*
* @param {any} entry
* @returns {string[]}
*/
export function resolveCategories(entry) {
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 */View on GitHub (pinned to 1696bec4d0)
Solutions
- Replace each category value with its URL slug, e.g. 'programming', 'machine-learning-ai'
- Lowercase and hyphenate multi-word categories ('Machine Learning' → 'machine-learning-ai')
- Ensure categories is a list of plain strings, not one comma-joined string
- Trim stray whitespace/slashes from each entry
Example fix
// before categories: ['Machine Learning', '/programming'] // after categories: ['machine-learning-ai', 'programming']
Defensive patterns
Strategy: validation
Validate before calling
const CATEGORY_SLUG_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
const cats = (cfg.categories ?? []).map(c => typeof c === 'string' ? c.trim() : c);
const bad = cats.filter(c => typeof c !== 'string' || !CATEGORY_SLUG_RE.test(c));
if (bad.length) throw new Error('Invalid getonbrd category slugs: ' + JSON.stringify(bad)); Type guard
function isValidCategorySlug(c) {
return typeof c === 'string' && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(c.trim());
} Try / catch
try {
const jobs = await getonbrdProvider.fetch(entry, ctx);
} catch (e) {
if (String(e.message).startsWith('getonbrd: invalid category')) {
console.error('Fix categories for', entry.name, '— use URL slugs like "programming"');
return [];
}
throw e;
} Prevention
- Copy slugs from getonbrd category URLs, never display names
- Normalize (lowercase, hyphenate, trim) categories when writing config
- Lint portals.yml category entries against the slug regex in CI
When it happens
Trigger: categories configured as 'Machine Learning', 'programming,design' (comma-joined single string), '/programming', 42, null inside the array, or an empty-string element.
Common situations: Copy-pasting human-readable category names from the getonbrd website instead of their URL slugs; YAML config quirks producing numbers or nested lists; trailing slashes from copying URLs.
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/7634df7bf942ea8d.
Report an issue: GitHub.