linshenkx/prompt-optimizer · error · CompareValidationError
Optimized text must be a string
Error message
Optimized text must be a string
What it means
Thrown by normalizeReferencePromptPreview after the model's text is parsed and constrained: JSON.stringify of the constrained object produced nothing or the literal 'null'. This means the parsed 'object' was not a serializable record (e.g. null, undefined, or JSON.stringify returned undefined for a non-object) even though earlier parsing appeared to succeed.
Source
Thrown at packages/core/src/services/compare/service.ts:69
throw error;
}
const errorMessage = error instanceof Error ? error.message : String(error);
throw new CompareCalculationError(
`Text comparison calculation failed: ${errorMessage}`
);
}
}
/**
* 验证输入参数
*/
private validateInput(original: string, optimized: string): void {
if (typeof original !== 'string') {
throw new CompareValidationError('Original text must be a string');
}
if (typeof optimized !== 'string') {
throw new CompareValidationError('Optimized text must be a string');
}
}
/**
* 执行文本对比 - 使用 jsdiff
*/
private performTextComparison(
original: string,
optimized: string,
options: CompareOptions
): TextFragment[] {
let diffResult: Change[];
// 根据配置处理文本预处理
let processedOriginal = original;
let processedOptimized = optimized;
if (options.ignoreWhitespace) {View on GitHub (pinned to 3e677b1d9f)
Solutions
- Strengthen the extraction prompt to demand a JSON object with specific keys
- Add an explicit isRecord check right after JSON.parse so failures surface earlier with clearer intent
- Retry the request; add 'Return only a JSON object, never null' to the system prompt
- Validate model output against a zod/schema before normalizing
Example fix
// before
const formattedPrompt = JSON.stringify(constrainedPromptObject, null, 2)
if (!formattedPrompt || formattedPrompt === 'null') {
throw new Error('Model response is not a valid JSON prompt object')
}
// after (reject non-records before serialization)
if (!isRecord(constrainedPromptObject)) {
throw new Error('Model response is not a valid JSON prompt object')
}
const formattedPrompt = JSON.stringify(constrainedPromptObject, null, 2) Defensive patterns
Strategy: retry
Validate before calling
// Pre-check the raw model text parses to a record before normalizing
function parsesToRecord(text: string): boolean {
try {
return isRecord(JSON.parse(text))
} catch {
return false
}
} Type guard
function isRecord(v: unknown): v is Record<string, unknown> {
return typeof v === 'object' && v !== null && !Array.isArray(v)
} Try / catch
try {
const preview = await extractor.resolveReferencePromptPreview(/* ... */)
} catch (error) {
if (error instanceof Error && error.message.includes('not a valid JSON prompt object')) {
return retryOnceOrElse(defaultPreview)
}
throw error
} Prevention
- Keep responseMimeType 'application/json' set on model calls
- Add an explicit 'respond with a JSON object, never null' instruction
- Validate model output with a schema (e.g. zod) before downstream processing
When it happens
Trigger: Calling resolveReferencePromptPreview where the model returns JSON like 'null', a bare string/number that parsed but wasn't a record, or an object whose serialization fails; constrainPromptVariables then yields null.
Common situations: Model outputs 'null' despite responseMimeType json; model wraps JSON in prose so extraction grabs the wrong fragment; upstream parse produced a non-record value; prompt changes causing the model to answer with a scalar.
Related errors
- CONTEXT_ERROR_CODES.IMPORT_FORMAT_ERROR
- Text comparison calculation failed: ${errorMessage}
- CONTEXT_ERROR_CODES.INVALID_STORE
AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27).
Data as JSON: /api/errors/27e04469fab8712f.
Report an issue: GitHub.