santifer/career-ops · error · Error

Profile photo not found or unreadable

Error message

Profile photo not found or unreadable: ${photo} (${err.code || err.message})

What it means

File-read failure in the CV HTML builder: the photo path resolved and passed the extension check, but readFile() threw while loading it. The interpolated err.code (e.g. ENOENT for a missing file, EACCES for permissions, EISDIR for a directory) names the OS-level cause. This is the only photo error wrapping an underlying filesystem error.

Solutions

  1. Check the path in the error message actually exists and is a regular file
  2. Fix directory permissions if err.code is EACCES
  3. Correct relative paths — non-absolute paths resolve against the script's __dirname, not the CWD
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at build-cv-html.mjs:157 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of santifer/career-ops@e7abd431fc (2026-09-16). Data as JSON: /api/errors/a8280649c37fb655. Report an issue: GitHub.

Appendix: source

Thrown at build-cv-html.mjs:157

    c.photo = photo;
    return c;
  }

  if (/^[a-z][a-z0-9+.-]+:/i.test(photo)) {
    throw new Error(`Unsupported profile photo URL scheme: ${photo.split(':', 1)[0]}`);
  }

  const photoPath = isAbsolute(photo) ? photo : resolve(__dirname, photo);
  const mime = PHOTO_MIME_BY_EXT.get(extname(photoPath).toLowerCase());
  if (!mime) {
    throw new Error(`Unsupported profile photo format: ${photo} (expected PNG, JPEG, WebP, or GIF)`);
  }

  let bytes;
  try {
    bytes = await readFile(photoPath);
  } catch (err) {
    throw new Error(`Profile photo not found or unreadable: ${photo} (${err.code || err.message})`);
  }
  if (bytes.length === 0) {
    throw new Error(`Profile photo is empty: ${photo}`);
  }
  c.photo = `data:${mime};base64,${bytes.toString('base64')}`;
  return c;
}

function joinItems(items) {
  if (Array.isArray(items)) return items.join(', ');
  return typeof items === 'string' ? items : '';
}

// ── Section partials (#2183) ────────────────────────────────────────────────
//
// Resolve the sections/ directory co-located with a given template file.
// For "templates/cv-template.html" this is "templates/sections/".
// For a custom pack at "templates/cv-template.compact.html" we look for

View on GitHub (pinned to e7abd431fc)