{"record":{"id":"bc9ab1f1033f3a59","repo":"bytedance/deer-flow","slug":"thread-history-returned-a-row-with-an-invalid-seq","errorCode":null,"errorMessage":"Thread history returned a row with an invalid seq.","messagePattern":"Thread history returned a row with an invalid seq\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/core/threads/hooks.ts","lineNumber":355,"sourceCode":"  if (typeof value !== \"object\" || value === null) {\n    throw new Error(\"Thread history returned an invalid response.\");\n  }\n\n  const data = Reflect.get(value, \"data\");\n  const hasMore = Reflect.get(value, \"has_more\");\n  const nextBeforeSeq = Reflect.get(value, \"next_before_seq\");\n  if (!Array.isArray(data) || typeof hasMore !== \"boolean\") {\n    throw new Error(\"Thread history returned an invalid response.\");\n  }\n\n  const seenSeqs = new Set<number>();\n  for (const row of data) {\n    const seq =\n      typeof row === \"object\" && row !== null\n        ? Reflect.get(row, \"seq\")\n        : undefined;\n    if (!isValidThreadMessageSeq(seq)) {\n      throw new Error(\"Thread history returned a row with an invalid seq.\");\n    }\n    if (seenSeqs.has(seq)) {\n      throw new Error(\"Thread history returned duplicate seq values.\");\n    }\n    seenSeqs.add(seq);\n  }\n\n  if (\n    (hasMore && !isValidThreadMessageSeq(nextBeforeSeq)) ||\n    (!hasMore && nextBeforeSeq !== null)\n  ) {\n    throw new Error(\n      \"Thread history returned an invalid next_before_seq cursor.\",\n    );\n  }\n\n  return value as ThreadMessagesPageResponse;\n}","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/frontend/src/core/threads/hooks.ts#L337-L373","documentation":"Thrown while validating each row of the thread history 'data' array. After confirming the payload shape, the parser checks every row's 'seq' field with isValidThreadMessageSeq. A row whose seq is missing, not a positive integer (or otherwise outside the accepted range) triggers this error, refusing to render a malformed history page.","triggerScenarios":"A row in the returned messages array is a primitive (string/number), or an object whose 'seq' is null, undefined, a non-integer, zero/negative, or a float. Happens when the backend serializer emits rows without seq (e.g. synthetic or draft messages inserted into the page) or when a float seq slips through from a DB mapping bug.","commonSituations":"Backend change that renames or drops the seq column in the messages payload, insertion of non-persisted placeholder messages into the history response, or a unit test fixture using {id: ...} instead of {seq: ...}.","solutions":["Log one offending row (JSON.stringify) from the /messages response and check its 'seq' value.","Fix the backend serializer (or fixture) so every row carries an integer seq within the valid range.","If seq can legitimately be absent for some row type, filter those rows server-side instead of shipping them in the page."],"exampleFix":"// before: row emitted without seq\n{\"data\": [{\"message_id\": \"m1\", \"content\": \"hi\"}], \"has_more\": false}\n\n// after: every row carries a valid integer seq\n{\"data\": [{\"seq\": 1, \"message_id\": \"m1\", \"content\": \"hi\"}], \"has_more\": false, \"next_before_seq\": null}","handlingStrategy":"type-guard","validationCode":"const rows = Array.isArray(body?.data) ? body.data : [];\nconst bad = rows.filter((r) => !(typeof r === \"object\" && r !== null && Number.isInteger((r as any).seq) && (r as any).seq > 0));\nif (bad.length) { /* log rows, refuse to render page */ }","typeGuard":"function isValidSeq(seq: unknown): seq is number {\n  return typeof seq === \"number\" && Number.isInteger(seq) && seq > 0;\n}\nfunction hasValidSeqs(rows: unknown[]): boolean {\n  return rows.every((r) => typeof r === \"object\" && r !== null && isValidSeq(Reflect.get(r, \"seq\")));\n}","tryCatchPattern":"catch (e) { if (e instanceof Error && e.message.includes(\"invalid seq\")) { reportDataIssue(threadId, e); } throw e; }","preventionTips":["Backend: enforce NOT NULL + UNIQUE(thread_id, seq) and integer seq in the schema.","Backend tests: assert every history row serializes with an integer seq.","Fixtures: lint test data for seq presence before running frontend tests."],"tags":["validation","threads","pagination","data-integrity"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}