linshenkx/prompt-optimizer · error · VariableValueGenerationParseError

values[${index}] is missing a valid "reason" field.

Error message

values[${index}] is missing a valid "reason" field.

What it means

Each generated value must include a string reason explaining the generated value. normalizeGenerationResponse throws with the item's index when item.reason is missing or not a string, completing the strict per-item contract of { name, value, reason }.

Source

Thrown at packages/core/src/services/variable-value-generation/service.ts:232

    // 🔧 对请求变量名也进行trim,避免首尾空格导致匹配失败
    const requestedNames = new Set(requestedVariables.map(v => v.name.trim()));

    // 标准化每个生成的值
    const rawValues: GeneratedVariableValue[] = data.values.map((item: any, index: number) => {
      if (!item || typeof item !== 'object') {
        throw new VariableValueGenerationParseError(`values[${index}] is not a valid object.`);
      }

      if (typeof item.name !== 'string' || !item.name.trim()) {
        throw new VariableValueGenerationParseError(`values[${index}] is missing a valid "name" field.`);
      }

      if (typeof item.value !== 'string') {
        throw new VariableValueGenerationParseError(`values[${index}] is missing a valid "value" field.`);
      }

      if (typeof item.reason !== 'string') {
        throw new VariableValueGenerationParseError(`values[${index}] is missing a valid "reason" field.`);
      }

      return {
        name: item.name.trim(),
        value: item.value,
        reason: item.reason,
        confidence: typeof item.confidence === 'number' ? item.confidence : undefined,
      };
    });

    // 🔧 对齐处理:过滤掉不在请求列表中的变量 + 建立Map用于快速查找
    const valueMap = new Map<string, GeneratedVariableValue>();
    for (const val of rawValues) {
      if (requestedNames.has(val.name)) {
        // 🔧 检测LLM返回的同名重复
        if (valueMap.has(val.name)) {
          console.warn(`[VariableValueGeneration] LLM returned a duplicate variable name: ${val.name}. The later value will overwrite the earlier one.`);
        }

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. Default-fill reason: '' in pre-processing if explanations are optional for your use case
  2. Remap alternate keys (item.why ?? item.explanation -> item.reason)
  3. Require reason explicitly in the template with an example item
  4. Raise max_tokens if responses end mid-item

Example fix

// before
const out = await gen.generate(req);

// after
const parsed = JSON.parse(text);
for (const item of parsed.values ?? []) {
  if (typeof item.reason !== 'string') item.reason = item.why ?? item.explanation ?? '';
}
Defensive patterns

Strategy: validation

Validate before calling

for (const item of parsed.values ?? []) { if (typeof item.reason !== 'string') item.reason = item.why ?? item.explanation ?? ''; }

Type guard

const hasReason = (item: any) => typeof item?.reason === 'string';

Try / catch

catch (e) { if (e instanceof VariableValueGenerationParseError && /reason. field/.test(e.message)) { /* default-fill reason and retry */ } throw e; }

Prevention

When it happens

Trigger: values[i] = { name: 'var1', value: 'x' } with no reason, or reason: 5 / reason: null / reason: { why: '...' }.

Common situations: Model drops reason to save tokens on long generations; customized template that removed the reason requirement; truncation cutting trailing fields; model nesting the explanation under a different key ('why', 'explanation').

Related errors


AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27). Data as JSON: /api/errors/5680342dbbca2f13. Report an issue: GitHub.