paperclipai/paperclip · error · PhotonAnswerValidationError

Write your custom answer as text

Error message

Write your custom answer as text

What it means

PhotonAnswerValidationError thrown when the numeric answer selects an option whose freeText flag is true. Free-text options are not selectable by number — a custom answer must be submitted as plain text, not as an option index.

Solutions

  1. Submit the custom answer as plain text instead of the freeText option's number
  2. Filter out freeText options when rendering selectable numbered options
  3. Combine the option selection only over non-freeText options

Example fix

// before
await answer(interaction, index, String(question.options.length)); // the "Other" option
// after
await answer(interaction, index, "my custom answer");
Defensive patterns

Strategy: validation

Validate before calling

const selectable = question.options.map((o, idx) => ({ o, idx })).filter(x => !x.o.freeText); if (selectedNumbers.some(n => question.options[n-1]?.freeText)) throw new Error('free-text option not selectable by number');

Type guard

const isFreeTextOption = (o: { freeText?: boolean }) => o.freeText === true;

Try / catch

try { return parsePhotonQuestionAnswer(interaction, i, value); } catch (e) { if (e instanceof PhotonAnswerValidationError && /custom answer as text/.test(e.message)) return submitFreeText(value); throw e; }

Prevention

When it happens

Trigger: Calling parsePhotonQuestionAnswer with a number pointing at the freeText option (e.g. the last "Other…" option) instead of providing the custom text directly.

Common situations: UI shows the free-text "Other" option numbered in the list and the user picks it by number; an agent enumerates all options including the freeText one.

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


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/413b7edb918717bc. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/photon/interactions.ts:109

      "Enter a nonempty answer within the task’s length limit",
    );
  const numbers =
    /^\d+(?:[ ,]+\d+)*$/.test(value) &&
    question.options.some((option) => !option.freeText)
      ? value.split(/[ ,]+/).map(Number)
      : null;
  if (numbers) {
    if (
      new Set(numbers).size !== numbers.length ||
      numbers.some((index) => index < 1 || index > question.options.length)
    )
      throw new PhotonAnswerValidationError(
        "Choose valid option numbers without duplicates",
      );
    if (question.selectionMode === "single" && numbers.length !== 1)
      throw new PhotonAnswerValidationError("Choose one option");
    if (numbers.some((index) => question.options[index - 1].freeText))
      throw new PhotonAnswerValidationError("Write your custom answer as text");
    return {
      questionId: question.id,
      optionIds: numbers.map((index) => question.options[index - 1].id),
    };
  }
  const freeText = question.options.find((option) => option.freeText);
  if (question.options.length && question.allowOther === false && !freeText)
    throw new PhotonAnswerValidationError(
      "Answer with the option number(s) shown in the prompt",
    );
  return {
    questionId: question.id,
    optionIds: freeText ? [freeText.id] : [],
    otherText: value,
  };
}
export function photonAnswersMatch(
  interaction: AskUserQuestionsInteraction,

View on GitHub (pinned to 3f1d897a7c)