{"record":{"id":"a137adc9a5b2d4f7","repo":"santifer/career-ops","slug":"apify-jd-cache-write-failed-for-normalized-titl","errorCode":null,"errorMessage":"apify: JD cache write failed for ${normalized.title} (${err.code || err.name}: ${err.message}); falling back to remote URL","messagePattern":"apify: JD cache write failed for (.+?) \\((.+?): (.+?)\\); falling back to remote URL","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"plugins/apify/index.mjs","lineNumber":153,"sourceCode":"    const today = new Date().toISOString().slice(0, 10);\n    const content = `---\ntitle: ${yamlEscape(normalized.title)}\ncompany: ${yamlEscape(normalized.company)}\nurl: ${yamlEscape(normalized.url)}\nlocation: ${yamlEscape(normalized.location)}\nscraped: \"${today}\"\nsource: ${sourceLabel}\n---\n\n# ${normalized.title} — ${normalized.company}\n\n${descriptionBody}\n`;\n    writeFileSync(filepath, content, { encoding: 'utf-8', flag: 'wx' });\n    return relPath;\n  } catch (err) {\n    if (err?.code === 'EEXIST' && relPath) return relPath;\n    console.warn(`apify: JD cache write failed for ${normalized.title} (${err.code || err.name}: ${err.message}); falling back to remote URL`);\n    return null;\n  }\n}\n\nexport function normalizeItem(item, fieldMap, defaults) {\n  const out = {\n    title: String(pickField(item, fieldMap.title) || ''),\n    url: String(pickField(item, fieldMap.url) || ''),\n    company: fieldMap.company ? String(pickField(item, fieldMap.company) || '') : '',\n    location: fieldMap.location ? String(pickField(item, fieldMap.location) || '') : '',\n  };\n  for (const [k, v] of Object.entries(defaults || {})) {\n    if (!ALLOWED_DEFAULT_KEYS.has(k)) continue;\n    if (!out[k]) out[k] = String(v);\n  }\n  return out;\n}\n","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/santifer/career-ops/blob/1696bec4d021768e7359f9aad6b329cba883da20/plugins/apify/index.mjs#L135-L171","documentation":"saveJd in plugins/apify/index.mjs caches scraped job descriptions to local files using writeFileSync with flag 'wx' (fail if the file already exists). On any write error other than the handled EEXIST case, it logs 'apify: JD cache write failed ... falling back to remote URL' and returns null so the pipeline can reference the remote posting URL instead of a local capture. This is a non-fatal degradation warning, not a crash.","triggerScenarios":"Calling saveJd when the target directory does not exist (ENOENT — the code creates the path from title/date but not parent dirs in all layouts), the process lacks write permission (EACCES/EPERM), the disk is full (ENOSPC), the path is invalid/too long (ENAMETOOLONG), or read-only filesystem (EROFS). EEXIST is explicitly tolerated and returns the existing relPath.","commonSituations":"Running the plugin in a read-only checkout or CI workspace where jds/ can't be created; disk quota exceeded after many scrapes; a job title with characters that produce an over-long or invalid filename; running from a different cwd so relative jds/ path resolves outside a writable area.","solutions":["Read the err.code in the warning (ENOENT → ensure the jds/ directory exists first, e.g. mkdirSync(dir, {recursive:true}); EACCES → fix permissions; ENOSPC → free disk space)","Sanitize/shorten the job title used for the filename to avoid ENAMETOOLONG or invalid characters","Ensure the script runs from the repository root (or make STATE/paths absolute) so the relative jds/ path lands in a writable location","Treat the warning as informational: the pipeline continues using the remote URL; fix the environment and rerun to get a local capture"],"exampleFix":"// before\nwriteFileSync(filepath, content, { encoding: 'utf-8', flag: 'wx' });\n// ENOENT because jds/ doesn't exist\n// after: ensure the directory exists before writing\nmkdirSync(path.dirname(filepath), { recursive: true });\nwriteFileSync(filepath, content, { encoding: 'utf-8', flag: 'wx' });","handlingStrategy":"fallback","validationCode":"import { existsSync, accessSync, constants, statSync } from 'fs';\nfunction cacheDirWritable(dir) {\n  if (!existsSync(dir)) return false; // caller must mkdir -p\n  try { accessSync(dir, constants.W_OK); return statSync(dir).isDirectory(); } catch { return false; }\n}\n// before saving: ensure dir exists and is writable, else expect the fallback warning","typeGuard":null,"tryCatchPattern":"const relPath = saveJd(item);\nif (relPath === null) {\n  // cache write failed — proceed with the remote URL instead\n  reference = item.url;\n} else {\n  reference = `local:${relPath}`;\n}","preventionTips":["mkdirSync(dir, { recursive: true }) before writing JD captures","Sanitize job titles for filename length and illegal characters","Run the pipeline from the repo root (or use absolute paths) so jds/ is in a writable location","Monitor disk space/quota in environments that scrape often"],"tags":["filesystem","cache-write","apify","degradation"],"backgroundTag":"file-write-failed","analyzedSha":"1696bec4d021768e7359f9aad6b329cba883da20","analyzedAt":"2026-09-01T19:19:23.111Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}