{"record":{"id":"589dcafc302475a3","repo":"sgl-project/sglang","slug":"missing-previous-frame-for-delta-payload","errorCode":null,"errorMessage":"Missing previous frame for delta payload","messagePattern":"Missing previous frame for delta payload","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/apps/realtime_webui/app.js","lineNumber":1079,"sourceCode":"async function gunzipBytes(payload) {\n  if (typeof DecompressionStream === \"undefined\") {\n    throw new Error(\"This browser does not support gzip stream decoding\");\n  }\n  const stream = new Blob([payload]).stream().pipeThrough(new DecompressionStream(\"gzip\"));\n  return new Uint8Array(await new Response(stream).arrayBuffer());\n}\n\nasync function restoreDeltaGzipRawRgb(header, payload) {\n  const frameBytes = Number(header.bytes_per_frame);\n  const count = Number(header.num_frames);\n  const expectedSize = frameBytes * count;\n  const restored = await gunzipBytes(payload);\n  if (restored.length !== expectedSize) {\n    throw new Error(`delta payload size mismatch: expected ${expectedSize}, got ${restored.length}`);\n  }\n  let previous = header.delta_reference === \"previous-frame\" ? lastRawRgbFrame : null;\n  if (header.delta_reference === \"previous-frame\" && !previous) {\n    throw new Error(\"Missing previous frame for delta payload\");\n  }\n  for (let f = 0; f < count; f++) {\n    const current = f * frameBytes;\n    if (previous) {\n      for (let i = 0; i < frameBytes; i++) {\n        restored[current + i] ^= previous[i];\n      }\n    }\n    previous = restored.slice(current, current + frameBytes);\n  }\n  return restored;\n}\n\nasync function framePayloadToImageData(header, payload) {\n  let rawPayload;\n  const isRgba = header.content_type === RAW_RGBA_DELTA_GZIP_CONTENT_TYPE;\n  if (\n    header.content_type === WEBP_FRAME_CONTENT_TYPE ||","sourceCodeStart":1061,"sourceCodeEnd":1097,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/apps/realtime_webui/app.js#L1061-L1097","documentation":"SuffixAutomaton::appendTokens refuses to add tokens once finalize() has been called (finalized_ flag). A finalized SAM is a read-only query structure for longest-match lookups, so appending would invalidate its internal indexes.","triggerScenarios":"Calling appendTokens() on a SuffixAutomaton after finalize() was invoked — e.g. trying to stream more prompt tokens into a SAM already finalized for matching, or reusing a SAM object across requests without reset.","commonSituations":"Reusing a per-request suffix automaton across generations without resetting, incremental corpus updates after the matcher was built, or control-flow bugs where finalize() runs early (e.g. in an error path) before the final appendTokens.","solutions":["Call reset()/re-create the SAM before appending new tokens after a finalize","Restructure so all appendTokens calls happen before the single finalize() call","Audit early-finalize paths (exceptions, early returns) if you believe the SAM shouldn't be finalized yet"],"exampleFix":"// before\nsam.appendTokens(prompt1); sam.finalize();\nsam.appendTokens(prompt2); // throws\n\n// after\nsam.appendTokens(prompt1); sam.finalize();\n// ... matching on prompt1 ...\nsam.reset();\nsam.appendTokens(prompt2); sam.finalize();","handlingStrategy":"validation","validationCode":"if sam.finalized:  # or track finalize() calls yourself\n    sam.reset()\nsam.appendTokens(tokens)","typeGuard":"def can_append(sam) -> bool:\n    return not getattr(sam, \"finalized_\", False) and not getattr(sam, \"is_finalized\", lambda: False)()","tryCatchPattern":"try:\n    sam.appendTokens(tokens)\nexcept RuntimeError as e:\n    if \"after finalizing\" in str(e):\n        sam.reset(); sam.appendTokens(tokens)\n    else:\n        raise","preventionTips":["One SAM per request/generation, or reset() between reuses","Keep a Python-side finalized flag mirroring the C++ state","Ensure finalize() is the last step of the build phase, after all appends"],"tags":["suffix-automaton","ngram","state-machine","api-misuse"],"backgroundTag":"operation-after-finalize","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}