santifer/career-ops · error · Error
teamtailor: untrusted hostname "${parsed.hostname}" — must b
Error message
teamtailor: untrusted hostname "${parsed.hostname}" — must be <slug>.teamtailor.com (or set "provider: teamtailor" to use a branded careers domain) What it means
assertFeedUrl's third check (skipped when explicit=true) requires the hostname to match TEAMTAILOR_HOST_RE, i.e. <slug>.teamtailor.com. A branded careers domain (e.g. careers.acme.com) is rejected unless the entry opts in with provider: teamtailor, which sets explicit=true and bypasses this check. This is the SSRF pin that keeps auto-detection on the trusted *.teamtailor.com host.
Source
Thrown at providers/teamtailor.mjs:42
const TEAMTAILOR_HOST_RE = /^([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\.teamtailor\.com$/i;
/**
* Validate a feed URL before fetching. Always HTTPS-only. The hostname is
* pinned to `*.teamtailor.com` for auto-detected entries; an explicit
* `provider: teamtailor` entry may use its configured branded host.
* @param {string} url
* @param {{ explicit?: boolean }} [opts]
*/
function assertFeedUrl(url, { explicit = false } = {}) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`teamtailor: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`teamtailor: URL must use HTTPS: ${url}`);
if (!explicit && !TEAMTAILOR_HOST_RE.test(parsed.hostname)) {
throw new Error(`teamtailor: untrusted hostname "${parsed.hostname}" — must be <slug>.teamtailor.com (or set "provider: teamtailor" to use a branded careers domain)`);
}
return url;
}
// Derive the RSS feed URL from a tracked_companies entry by normalizing any
// path on the configured host to /jobs.rss. Auto-detection (explicit=false)
// only claims *.teamtailor.com hosts; an explicit `provider: teamtailor` entry
// (explicit=true) may use a branded careers host. Returns null otherwise.
/**
* @param {import('./_types.js').PortalEntry} entry
* @param {{ explicit?: boolean }} [opts]
*/
function resolveFeedUrl(entry, { explicit = false } = {}) {
const raw = entry?.api || entry?.careers_url || '';
if (typeof raw !== 'string' || !raw) return null;
let parsed;
try {
parsed = new URL(raw);View on GitHub (pinned to 9b17a8ac97)
Solutions
- Add provider: teamtailor to the entry so the branded host is honored (explicit=true)
- Or point careers_url at the canonical https://<slug>.teamtailor.com host
- Verify the branded host actually serves /jobs.rss before relying on it
Example fix
# before - name: Acme careers_url: https://careers.acme.com # after - name: Acme provider: teamtailor careers_url: https://careers.acme.com
Defensive patterns
Strategy: validation
Validate before calling
// For branded hosts, require the explicit opt-in before fetch.
const TT_RE = /^([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\.teamtailor\.com$/i;
const raw = entry.api || entry.careers_url || '';
let parsed; try { parsed = new URL(raw); } catch { parsed = null; }
const explicit = entry.provider === 'teamtailor';
if (parsed && !explicit && !TT_RE.test(parsed.hostname)) {
console.warn(`${entry.name}: branded host needs provider: teamtailor to be used`);
} Prevention
- For any non-*.teamtailor.com host, always set provider: teamtailor.
- Confirm the branded host actually serves /jobs.rss before relying on it.
- Lint entries whose careers_url host is not *.teamtailor.com and lacks the provider opt-in.
When it happens
Trigger: An auto-detected entry's careers_url points at a branded domain rather than *.teamtailor.com, and no provider: teamtailor opt-in is set. The provider will not auto-claim an arbitrary branded host.
Common situations: A company fronts the same RSS feed on a custom domain; the user added the branded URL expecting detection. The supported workaround is the explicit provider opt-in.
Related errors
- solidjobs: untrusted hostname "${parsed.hostname}" — must be
- teamtailor: invalid URL: ${url}
- teamtailor: URL must use HTTPS: ${url}
- tkms: cannot resolve jobs host for ${entry.name}
- flowxtra: untrusted hostname "${parsed.hostname}" — must be
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/bc59ba21b44b7a4c.
Report an issue: GitHub.