santifer/career-ops · error · Error
version must be a positive integer
Error message
version must be a positive integer
What it means
applicationArtifactPaths validates that the version parameter is a positive integer before constructing versioned directory paths (e.g. cv/tailored/v001). It regex-checks that version is all digits and that its numeric value is >= 1, throwing this error when either check fails. This guarantees the padded vNNN directory name is always well-formed.
Solutions
- Pass version as a plain integer >= 1 (e.g. applicationArtifactPaths({ reportNum: 42, company: 'Acme', role: 'Engineer', version: 2 })).
- If the version comes as a string, strip non-digits and parse first: parseInt(String(raw).replace(/\D/g,''), 10), then check > 1 before calling.
- Check for a counter that starts at 0 and was never incremented, or an off-by-one where version 0 is used to mean 'first' — the first version is 1.
- If the value may legitimately be absent, pass undefined (the default of 1 applies) rather than null or ''.
Example fix
// before
const paths = applicationArtifactPaths({ reportNum: 42, company: 'Acme', role: 'Eng', version: 'v2' });
// after
const version = parseInt(String(rawVersion).replace(/^v/, ''), 10);
if (Number.isInteger(version) && version >= 1) {
const paths = applicationArtifactPaths({ reportNum: 42, company: 'Acme', role: 'Eng', version });
} Defensive patterns
Strategy: validation
Validate before calling
function isValidVersion(v) {
return /^\d+$/.test(String(v)) && Number(v) >= 1;
}
if (!isValidVersion(version)) throw new Error(`bad version: ${JSON.stringify(version)}`); Type guard
const isPositiveInt = (v) => Number.isInteger(Number(v)) && Number(v) >= 1 && /^\d+$/.test(String(v));
Try / catch
let paths;
try {
paths = applicationArtifactPaths({ reportNum, company, role, version });
} catch (err) {
if (err.message.includes('version must be')) {
console.error(`Invalid version ${JSON.stringify(version)}, falling back to 1`);
paths = applicationArtifactPaths({ reportNum, company, role, version: 1 });
} else throw err;
} Prevention
- Always pass version as a plain integer, never a 'v'-prefixed or zero-padded string.
- Coerce query/config string inputs with parseInt before calling.
- Remember the default is 1 — pass undefined rather than null/'' when the value is unknown.
- Unit-test path builders with boundary inputs (0, -1, '1.5', '').
When it happens
Trigger: Calling applicationArtifactPaths with version = 0, a negative number, a non-numeric string (e.g. 'v2', 'latest', 'v'), a float like 1.5, null/undefined passed explicitly where defaults are bypassed (destructuring default only applies to undefined), or an empty string.
Common situations: Storing the version as a zero-padded string in config and passing it back without parsing ('002' actually works, but 'v002' fails); a caller reading version from a URL query param that can be '' or '0'; arithmetic producing 0 because a counter was never incremented; passing a semantic version string like '1.2'.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- changedSections must be an array
- decision must be one of
- getEmployerProfile: id is required
- getEmployerProfile: id is required
- USAGE
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/287de8d0db5ae9fe.
Report an issue: GitHub.
Appendix: source
Thrown at application-artifacts.mjs:36
const DECISIONS = new Set(['reuse', 'reuse-with-edits', 'regenerate']);
/** Convert a user-facing label into a safe, readable path segment. */
export function slugifySegment(value, fallback = 'application') {
const slug = String(value ?? '')
.trim()
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '');
return slug || fallback;
}
/** Return all stable paths belonging to one application artifact bundle. */
export function applicationArtifactPaths({ reportNum, company, role, version = 1, root = DEFAULT_OUTPUT_ROOT }) {
if (!/^\d+$/.test(String(reportNum ?? ''))) {
throw new Error('reportNum must be a numeric report number');
}
if (!/^\d+$/.test(String(version ?? '')) || Number(version) < 1) {
throw new Error('version must be a positive integer');
}
const key = `${String(reportNum).padStart(3, '0')}-${slugifySegment(company)}-${slugifySegment(role, 'role')}`;
const applicationRoot = join(resolve(root), key);
const tailoredRoot = join(applicationRoot, 'cv', 'tailored', `v${String(version).padStart(3, '0')}`);
return {
key,
root: applicationRoot,
jd: {
current: join(applicationRoot, 'jd', 'current.md'),
previous: join(applicationRoot, 'jd', 'previous.md'),
},
cv: {
source: {
html: join(applicationRoot, 'cv', 'source', 'original.html'),
pdf: join(applicationRoot, 'cv', 'source', 'original.pdf'),
},
tailored: {
root: tailoredRoot,View on GitHub (pinned to aac998c7ed)