paperclipai/paperclip · error · PhotonAnswerValidationError

This question requires an answer

Error message

This question requires an answer

What it means

PhotonAnswerValidationError thrown when the answer value is exactly the string "skip" (case-insensitive) but the question is not optional — required is anything other than false. Skipping is only permitted for questions explicitly marked required: false.

Solutions

  1. Provide an actual answer (option number or free text) instead of "skip"
  2. Only send "skip" when question.required === false
  3. If the question should be skippable, update the interaction payload to set required: false and republish

Example fix

// before
await answer(interaction, index, "skip");
// after
if (question.required !== false) throw new Error("answer required");
await answer(interaction, index, "skip");
Defensive patterns

Strategy: validation

Validate before calling

if (value.toLowerCase() === 'skip' && question.required !== false) throw new Error('this question requires an answer');

Type guard

const canSkip = (q: { required?: boolean }): boolean => q.required === false;

Try / catch

try { return parsePhotonQuestionAnswer(interaction, i, value); } catch (e) { if (e instanceof PhotonAnswerValidationError && e.message === 'This question requires an answer') return promptUserForAnswer(question); throw e; }

Prevention

When it happens

Trigger: Answering a required ask_user_questions question with the literal text "skip" via parsePhotonQuestionAnswer/processPhotonResponse.

Common situations: Agent or user tries to dodge a required question by typing "skip"; a UI offers a skip button without checking question.required; copied answer text from an optional question applied to a required one.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

  if (!match) return null;
  return {
    command: match[1].toLowerCase() as "answer" | "submit",
    reference: match[2],
    questionIndex: Number(match[3] ?? 1) - 1,
    value: match[4]?.trim() ?? "",
  };
}
export function parsePhotonQuestionAnswer(
  interaction: AskUserQuestionsInteraction,
  questionIndex: number,
  value: string,
): AskUserQuestionsAnswer {
  const question = interaction.payload.questions[questionIndex];
  if (!question)
    throw new PhotonAnswerValidationError("That question does not exist");
  if (value.toLowerCase() === "skip") {
    if (question.required !== false)
      throw new PhotonAnswerValidationError("This question requires an answer");
    return { questionId: question.id, optionIds: [] };
  }
  if (!value || value.length > 100_000)
    throw new PhotonAnswerValidationError(
      "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",

View on GitHub (pinned to 3f1d897a7c)