santifer/career-ops · error · Error
oraclecloud: invalid URL: ${url}
Error message
oraclecloud: invalid URL: ${url} What it means
Thrown by oraclecloud's assertOracleUrl() when new URL(url) raises — the URL string is syntactically unparseable. This is the first of three SSRF gates (valid URL → HTTPS → trusted hostname regex) that pin Oracle Cloud (ORC) career site fetches to legitimate *.fa.*.oraclecloud.com hosts. Unlike simpler providers, the trusted-host check uses a regex (ORACLE_HOST_RE) because Oracle career sites have tenant-specific subdomains.
Source
Thrown at providers/oraclecloud.mjs:66
// oraclecloud99.com. No leading zero, at most two digits — a bounded family,
// so this stays a host pin and never becomes a wildcard apex match.
const ORACLE_HOST_RE = /^[a-z0-9-]+\.fa\.(?:[a-z0-9-]+\.)?(?:ocs\.)?oraclecloud(?:[1-9][0-9]?)?\.com$/i;
const PAGE_SIZE = 200;
const MAX_PAGES = 25; // safety cap (~5000 jobs); hard ceiling like workday
const RETRY_POLICY = { retries: 3 };
const INTER_PAGE_DELAY_MS = 150; // WAF-aware spacing between same-host pages
// facetsList is a fixed constant on the finder; %3B is the encoded ';' separator.
const FACETS_LIST = 'LOCATIONS%3BWORK_LOCATIONS%3BWORKPLACE_TYPES%3BTITLES%3BCATEGORIES%3BORGANIZATIONS%3BPOSTING_DATES%3BFLEX_FIELDS';
/** @param {string} url */
function assertOracleUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`oraclecloud: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`oraclecloud: URL must use HTTPS: ${url}`);
if (!ORACLE_HOST_RE.test(parsed.hostname)) {
throw new Error(`oraclecloud: untrusted hostname "${parsed.hostname}" — must match *.fa[.<region>][.ocs].oraclecloud[1-99].com`);
}
return url;
}
// NaN-safe Date.parse — `|| undefined` would also coerce a valid epoch 0.
// (copied from greenhouse.mjs)
function toEpochMs(value) {
if (!value) return undefined;
const parsed = Date.parse(value);
return Number.isNaN(parsed) ? undefined : parsed;
}
function sleep(ms, ctx) {
if (typeof ctx?.sleep === 'function') return ctx.sleep(ms);View on GitHub (pinned to 9b17a8ac97)
Solutions
- Inspect the url argument: log it before assertOracleUrl to see the malformed value.
- Ensure the portals.yml oraclecloud entry has a valid https:// careers_url or api in the form https://<tenant>.fa.<region>.oraclecloud.com/hcmUI/CandidateExperience/...
- If calling fetch() directly, verify resolveSite(entry) returns a valid site object first.
Example fix
// before — entry has a malformed URL
job_boards:
oracle:
provider: oraclecloud
careers_url: 'oraclecloud.com/hcmUI/...' // missing https:// and tenant
// after
job_boards:
oracle:
provider: oraclecloud
careers_url: 'https://acme.fa.eu.oraclecloud.com/hcmUI/CandidateExperience/en/sites/CX_1' Defensive patterns
Strategy: validation
Validate before calling
/** Validate a URL string is parseable before passing to assertOracleUrl. */
function isValidUrlString(url) {
return typeof url === 'string'
&& url.length > 0
&& (() => { try { new URL(url); return true; } catch { return false; } })();
}
if (!isValidUrlString(entry.api) && !isValidUrlString(entry.careers_url)) {
console.warn(`oraclecloud entry ${entry.name} has no valid URL`);
continue;
} Type guard
/** @param {unknown} url @returns {url is string} */
function isParseableUrl(url) {
if (typeof url !== 'string' || !url) return false;
try { new URL(url); return true; } catch { return false; }
} Try / catch
try {
await oracleProvider.fetch(entry, ctx);
} catch (err) {
if (String(err.message).startsWith('oraclecloud: invalid URL')) {
console.warn(`skipping oraclecloud entry ${entry.name}: malformed URL`);
continue;
}
throw err;
} Prevention
- Validate URL fields in portals.yml at config-load time.
- Ensure Oracle HCM career URLs include the full https://<tenant>.fa.<region>.oraclecloud.com path.
- Call detect(entry) and skip null results before calling fetch().
When it happens
Trigger: Called with a value new URL() cannot parse: undefined, empty string, a URL with spaces, or a schemeless path. The guard is invoked from fetch() before each page request (line: assertOracleUrl(apiUrl)), so it fires if buildApiUrl() produces a malformed URL — though buildApiUrl constructs from a validated host, so the more likely path is a direct/test call with bad input.
Common situations: A portals.yml oraclecloud entry has api or careers_url left empty or mistyped. A programmatic entry construction passes a non-string. Testing with a relative or fixture path. The resolveSite() function returned a host that, combined with buildApiUrl's path segments, produces an unparseable URL (unlikely but possible if the host contains illegal characters).
Related errors
- oraclecloud: 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/dd028b5327cb46e7.
Report an issue: GitHub.