{"record":{"id":"0645075912a68dd5","repo":"sgl-project/sglang","slug":"no-frames-were-recorded","errorCode":null,"errorMessage":"No frames were recorded","messagePattern":"No frames were recorded","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/apps/realtime_webui/app.js","lineNumber":559,"sourceCode":"    recordingTimer = 0;\n  }\n  recordingSaving = true;\n  updateRecordButton();\n\n  let fileHandle = null;\n  const fileName = recordingFileName();\n  try {\n    if (window.showSaveFilePicker) {\n      fileHandle = await window.showSaveFilePicker({\n        suggestedName: fileName,\n        types: [{\n          description: \"MP4 video\",\n          accept: { \"video/mp4\": [\".mp4\"] },\n        }],\n      });\n    }\n    await recordingEncodeChain;\n    if (!recordingEncoder || !recordingSamples.length) throw new Error(\"No frames were recorded\");\n    await recordingEncoder.flush();\n    const mp4Blob = buildRecordingMp4();\n    if (fileHandle) {\n      const writable = await fileHandle.createWritable();\n      await writable.write(mp4Blob);\n      await writable.close();\n    } else {\n      downloadBlob(mp4Blob, fileName);\n    }\n    addHistory(`saved ${recordingSamples.length} frames as mp4`);\n  } catch (error) {\n    if (error?.name === \"AbortError\") {\n      addHistory(\"recording save canceled\");\n    } else {\n      addHistory(error.message || \"recording save failed\");\n      setStatus(\"Save failed\", \"error\");\n    }\n  } finally {","sourceCodeStart":541,"sourceCodeEnd":577,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/apps/realtime_webui/app.js#L541-L577","documentation":"Thrown by the ngram_corpus JIT FFI write_result_ helper when the caller-provided out_mask tensor's first dimension is smaller than the mask vector produced by the matcher. The C++ side memcpy's result.mask into the pre-allocated output buffer, so it defensively checks capacity first and refuses to overflow the tensor.","triggerScenarios":"Calling batch_match_stateful (the stateful n-gram batch match FFI entry) with an out_mask tensor whose size(0) is smaller than the number of mask entries the kernel produced for the matched batch — e.g. allocating outputs from a stale/estimated batch size instead of the actual match result size, while out_tokens happens to be large enough.","commonSituations":"Reusing output buffers sized for a previous smaller batch, computing out_mask's shape from a different quantity (tokens vs mask length) than the kernel writes, or a Python-side size calculation drifting out of sync with the C++ matcher after a version bump of the JIT kernel.","solutions":["Check the FFI contract: out_mask must have size(0) >= result.mask.size(); allocate it with the exact expected mask length returned/agreed by batch_match_stateful before the call","If the kernel reports the required size (or a paired output-size FFI), query it first and allocate outputs from that value instead of estimating","Rebuild/reinstall the JIT extension (python -m sglang.kernels.jit build or equivalent) so Python bindings and C++ sources are from the same commit","Report upstream if the mask length is genuinely nondeterministic relative to the documented output shape"],"exampleFix":"// before\nout_mask = torch.empty(old_batch_size, dtype=torch.uint8, device=\"cuda\")\nffi.batch_match_stateful(state, tokens, out_tokens, out_mask)\n\n// after\nout_mask = torch.empty(expected_mask_len, dtype=torch.uint8, device=\"cuda\")\nassert out_mask.size(0) >= ffi.required_mask_size(state)\nffi.batch_match_stateful(state, tokens, out_tokens, out_mask)","handlingStrategy":"validation","validationCode":"expected = ffi.mask_output_size(state, tokens)  # or the documented fixed relation\nif out_mask.size(0) < expected:\n    out_mask = torch.empty(expected, dtype=torch.uint8, device=out_mask.device)\n# only then call batch_match_stateful","typeGuard":null,"tryCatchPattern":"try:\n    ffi.batch_match_stateful(...)\nexcept RuntimeError as e:\n    if \"out_mask buffer too small\" in str(e):\n        raise ValueError(f\"out_mask must have >= matcher mask size; got {out_mask.size(0)}\") from e\n    raise","preventionTips":["Allocate output tensors from the matcher-reported sizes, never from heuristic estimates","Keep Python-side shape math in one helper shared by all call sites","Assert tensor shapes in debug builds before FFI calls"],"tags":["ngram","ffi","buffer-size","cuda-kernel","tensor-shape"],"backgroundTag":"output-buffer-too-small","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}