{"record":{"id":"7ed4798d17b679ff","repo":"santifer/career-ops","slug":"torre-invalid-url-url","errorCode":null,"errorMessage":"torre: invalid URL: ${url}","messagePattern":"torre: invalid URL: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/torre.mjs","lineNumber":90,"sourceCode":"// Values the API accepts for the required `skill/role.experience` companion,\n// confirmed live; anything else is rejected server-side. Every one returns the\n// same result set, so the default is arbitrary among them.\nconst EXPERIENCE_LEVELS = new Set([\n  'potential-to-develop',\n  '1-plus-year',\n  '2-plus-years',\n  '3-plus-years',\n  '5-plus-years',\n]);\nconst DEFAULT_EXPERIENCE = '1-plus-year';\n\n/** @param {string} url */\nfunction assertTorreUrl(url) {\n  let parsed;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`torre: invalid URL: ${url}`);\n  }\n  if (parsed.protocol !== 'https:') throw new Error(`torre: URL must use HTTPS: ${url}`);\n  if (parsed.hostname !== TRUSTED_API_HOST) {\n    throw new Error(`torre: untrusted hostname \"${parsed.hostname}\" — must be ${TRUSTED_API_HOST}`);\n  }\n  return url;\n}\n\n/**\n * Build the search body from the portal entry. Only filters proven to affect\n * `total` are emitted — see the header note. Exported for tests.\n *\n * @param {any} entry\n * @returns {object}\n */\nexport function buildTorreQuery(entry) {\n  /** @type {Record<string, unknown>} */\n  const body = {};","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/santifer/career-ops/blob/1696bec4d021768e7359f9aad6b329cba883da20/providers/torre.mjs#L72-L108","documentation":"assertTorreUrl validates every URL the Torre provider will touch: it must parse as a URL, be HTTPS, and its hostname must equal the trusted Torre API host. This error is thrown when the string cannot be parsed by new URL() at all — missing scheme, spaces, malformed syntax — so no protocol/host checks can even run.","triggerScenarios":"Calling assertTorreUrl with a bare hostname like 'torre.ai', a relative path '/jobs', an empty/whitespace string, a URL with invalid characters, or a non-string coerced badly; config entries with unquoted YAML values that lose scheme or get mangled.","commonSituations":"Config value written without 'https://' because the author assumed a default; YAML special characters breaking the value; a template placeholder left unfilled; pasting a link from a messaging app that stripped the scheme.","solutions":["Prefix the URL with https:// if only a hostname or path was given.","Inspect the raw string (the message echoes it) for typos, spaces, or mangled YAML quoting and fix it at the source.","Ensure the value is an actual string — check for null/undefined config fields that interpolate into 'undefined'.","If the URL is user/third-party supplied, validate or normalize it before handing it to the Torre provider."],"exampleFix":"// before\nassertTorreUrl('torre.ai/jobs');\n// Error: torre: invalid URL: torre.ai/jobs\n// after\nassertTorreUrl('https://torre.ai/jobs');","handlingStrategy":"validation","validationCode":"function isParseableUrl(url) {\n  if (typeof url !== 'string' || !url.trim()) return false;\n  try { new URL(url); return true; } catch { return false; }\n}\nif (!isParseableUrl(torreUrl)) torreUrl = 'https://' + torreUrl; // normalize bare hosts","typeGuard":"function isAbsoluteHttpUrl(v) {\n  if (typeof v !== 'string') return false;\n  try { const u = new URL(v); return u.protocol === 'http:' || u.protocol === 'https:'; }\n  catch { return false; }\n}","tryCatchPattern":"try {\n  assertTorreUrl(raw);\n} catch (err) {\n  if (String(err.message).startsWith('torre: invalid URL:')) {\n    console.error(`Malformed URL in config, fix the scheme/syntax: ${err.message}`);\n  } else throw err;\n}","preventionTips":["Always store full absolute URLs (with https://) in config — never bare hostnames.","Quote YAML values containing special characters so the scheme isn't mangled.","Normalize input at the edge: prepend https:// to hostname-only strings before storing.","Never interpolate possibly-undefined config values into URLs."],"tags":["url-validation","config","validation"],"backgroundTag":"malformed-url","analyzedSha":"1696bec4d021768e7359f9aad6b329cba883da20","analyzedAt":"2026-09-01T19:19:23.111Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}