linshenkx/prompt-optimizer · error · VariableExtractionParseError

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

Error message

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

What it means

Each extracted variable must carry a human-readable reason string explaining why it was chosen as a variable. normalizeExtractionResponse throws this when variables[i].reason is missing or not a string, since the reason is part of the service's return contract.

Source

Thrown at packages/core/src/services/variable-extraction/service.ts:239

      if (!variable.position || typeof variable.position !== 'object') {
        throw new VariableExtractionParseError(`variables[${index}] is missing a valid "position" object.`);
      }

      if (typeof variable.position.originalText !== 'string') {
        throw new VariableExtractionParseError(
          `variables[${index}].position is missing a valid "originalText" field.`
        );
      }

      if (typeof variable.position.occurrence !== 'number') {
        throw new VariableExtractionParseError(
          `variables[${index}].position is missing a valid "occurrence" number.`
        );
      }

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

      return {
        name: variable.name.trim(),
        value: variable.value,
        position: {
          originalText: variable.position.originalText,
          occurrence: variable.position.occurrence,
        },
        reason: variable.reason,
        category: variable.category ? String(variable.category) : undefined,
      };
    });

    return {
      variables,
      summary: data.summary.trim(),
    };

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. Update the extraction template so every variable object explicitly includes a 'reason' string
  2. Default-fill reason when pre-processing the response if it's unimportant to your flow
  3. Verify the template 'variable-extraction' content in your template manager matches the expected schema
  4. Increase max_tokens if responses are being truncated mid-object

Example fix

// before
await service.parseExtractionResult(text);

// after
const parsed = JSON.parse(text);
for (const v of parsed.variables ?? []) {
  if (typeof v.reason !== 'string') v.reason = 'auto-filled: extracted by model';
}
await service.parseExtractionResult(JSON.stringify(parsed));
Defensive patterns

Strategy: validation

Validate before calling

for (const v of parsed.variables ?? []) { if (typeof v.reason !== 'string') v.reason = ''; }

Type guard

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

Try / catch

catch (e) { if (e instanceof VariableExtractionParseError && e.message.includes('reason')) { /* default-fill and re-parse */ } throw e; }

Prevention

When it happens

Trigger: variables[i] has no 'reason' key, or reason is a number/object/null (e.g. reason: 5 or reason: {"why": "..."}).

Common situations: Prompt template that never asked for a reason field; model abbreviates the response and drops optional-looking fields; older template versions with a different schema; max_tokens truncation cutting off trailing fields.

Related errors


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