{"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/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/plugins/apify/index.mjs#L135-L171","documentation":"Warning in plugins/apify/index.mjs's saveJd: writing the normalized JD markdown capture into the jds/ cache with flag 'wx' failed for a reason other than EEXIST. The plugin logs the error code/name plus message and returns null so the pipeline keeps the remote URL instead of the local capture.","triggerScenarios":"writeFileSync(flag:'wx') throws ENOENT (jds/ directory doesn't exist yet), EACCES (no write permission), or ENOSPC; relPath was not set so even EEXIST can't be short-circuited.","commonSituations":"Fresh clone without a jds/ directory; read-only volume; job titles with characters that break path construction (slashes) producing an invalid filepath; disk quota exceeded during a large Apify run.","solutions":["Create the cache directory: mkdir -p jds","Sanitize normalized.title before building filepath (strip '/', ':', control chars)","Check err.code in the warning: EACCES → fix permissions, ENOSPC → free disk space","Re-run the plugin; failure is non-fatal (remote URL fallback keeps the pipeline moving)"],"exampleFix":"// before\nwriteFileSync(filepath, content, { encoding: 'utf-8', flag: 'wx' });\n// after\nmkdirSync(dirname(filepath), { recursive: true });\nconst safeName = normalized.title.replace(/[^a-z0-9-_ ]/gi, '-').slice(0, 80);\nwriteFileSync(filepath, content, { encoding: 'utf-8', flag: 'wx' });","handlingStrategy":"validation","validationCode":"import { mkdirSync } from 'fs';\nmkdirSync('jds', { recursive: true }); // before any saveJd call\nconst safe = title.replace(/[^\\w\\-. ]+/g, '-').slice(0, 100);","typeGuard":"function safeFilename(name) { return typeof name === 'string' && name.replace(/[\\\\/:*?\"<>|]/g, '').trim().length > 0 ? name : 'untitled'; }","tryCatchPattern":"try { writeFileSync(filepath, content, { flag: 'wx' }); } catch (err) { if (err.code === 'EEXIST') return relPath; console.warn(`JD cache write failed: ${err.message}`); return null; }","preventionTips":["Create jds/ at plugin startup, not per write","Sanitize job titles (strip slashes, control chars) before building filenames","Use 'wx' intentionally: treat EEXIST as a cache hit, not an error","Watch for ENOSPC in long Apify batch runs"],"tags":["nodejs","filesystem","apify","jd-archive"],"backgroundTag":"file-write-failed","analyzedSha":"aac998c7ed7248ea853b720ceeb1fdbeb322fc5d","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}