santifer/career-ops · error
Gemini returned an invalid career-ops report
Error message
Gemini returned an invalid career-ops report: ${issues.join('; ')} What it means
validateEvaluationShape in gemini-eval.mjs collects all structural problems found in the model's returned report (missing sections, non-numeric or out-of-range SCORE_SUMMARY score, etc.) and throws once with every issue joined by ';'. It guarantees the Gemini output conforms to the career-ops report contract before it is used downstream.
Solutions
- Re-run the evaluation — non-deterministic model output often passes on retry.
- Check the listed issue(s) and adjust the prompt/temperature to enforce the exact report template.
- Pin a model version whose output format is known-good, and lower temperature for structured output.
- Add explicit few-shot output-format instructions or a response schema if the API supports one.
Example fix
// before const score = '4/5'; // model output, rejected // after (prompt addition) "SCORE_SUMMARY score MUST be a bare number between 0 and 5, e.g. `Score: 4.2`"
Defensive patterns
Strategy: try-catch
Validate before calling
function looksLikeReport(text) { return typeof text === 'string' && /SCORE_SUMMARY/i.test(text) && /Score:\s*\d+(\.\d+)?/.test(text); } Type guard
const isValidScore = (v) => typeof v === 'number' && Number.isFinite(v) && v >= 0 && v <= 5;
Try / catch
try { validateEvaluationShape(report); } catch (e) { if (/invalid career-ops report/.test(e.message)) { retryWithReinforcedPrompt(); } else throw e; } Prevention
- Pin a known-good model version and low temperature for structured output.
- Include the exact report template in the prompt with explicit numeric-score constraints.
- Parse the model output defensively and re-prompt on failure rather than accepting malformed output.
- Log the raw response alongside issues to spot format drift early.
When it happens
Trigger: The Gemini API response parsed but violated the expected report shape: a missing required section, SCORE_SUMMARY score absent/non-numeric/negative/above 5, or multiple rule violations accumulated in `issues`.
Common situations: Model version drift producing a re-formatted answer; a truncated response cutting off required sections; a prompt/temperature change making the model output prose instead of the structured template; a score given as '4/5' or 'good' instead of a number.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- apify: entry has invalid field_map. Each of title, url…
- Existing candidates file at
- invalid golden case : need string id/jd and label.
- Malformed states file at
- payload.articleDigest requires
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/6489361f1022f4d9.
Report an issue: GitHub.
Appendix: source
Thrown at gemini-eval.mjs:285
} else {
const summaryBlock = summary[1];
for (const key of ['COMPANY', 'ROLE', 'ARCHETYPE', 'LEGITIMACY']) {
const field = summaryBlock.match(new RegExp(`^\\s*${key}:\\s*(.+)$`, 'mi'));
const value = field?.[1]?.trim() ?? '';
if (!value || (key !== 'COMPANY' && value.toLowerCase() === 'unknown')) {
issues.push(`SCORE_SUMMARY ${key} is required`);
}
}
const score = summaryBlock.match(/^\s*SCORE:\s*([0-9]+(?:\.[0-9]+)?)/mi);
const scoreValue = score ? Number(score[1]) : NaN;
if (!Number.isFinite(scoreValue) || scoreValue < 0 || scoreValue > 5) {
issues.push('SCORE_SUMMARY score must be a number between 0 and 5');
}
}
if (issues.length > 0) {
throw new Error(`Gemini returned an invalid career-ops report: ${issues.join('; ')}`);
}
}
function slugifyCompany(value) {
return String(value || '')
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-|-$/g, '') || 'unknown';
}
/**
* Whether a value is a complete http(s) URL, and so can become a dedup key.
* @param {string} value - Candidate posting URL.
* @returns {boolean} True only for a parseable http/https URL with a host.
*/
function isPostingUrl(value) {
try {
const parsed = new URL(value);View on GitHub (pinned to aac998c7ed)