{"record":{"id":"862860778903d402","repo":"can1357/oh-my-pi","slug":"snapcompact-shape-was-not-resolved-before-renderin","errorCode":null,"errorMessage":"snapcompact shape was not resolved before rendering.","messagePattern":"snapcompact shape was not resolved before rendering\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/session/session-maintenance.ts","lineNumber":918,"sourceCode":"\t\t\t// fits without the warning loop (issue #3247). A local blocker rejects\n\t\t\t// this method, allowing the configured preference order to continue.\n\t\t\tlet snapcompactResult: snapcompact.CompactionResult | undefined;\n\t\t\tif (snapcompactReady) {\n\t\t\t\tconst maxFrames = this.#computeSnapcompactMaxFrames(preparation, effectiveSettings);\n\t\t\t\tif (maxFrames < 1) {\n\t\t\t\t\tlogger.warn(\"Snapcompact skipped: kept history alone exceeds the context budget\", {\n\t\t\t\t\t\tmodel: this.#model?.id,\n\t\t\t\t\t});\n\t\t\t\t\tthis.#host.emitNotice(\n\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\"snapcompact: kept history alone exceeds the context budget.\",\n\t\t\t\t\t\t\"compaction\",\n\t\t\t\t\t);\n\t\t\t\t\tthrow new Error(\"snapcompact cannot run locally: kept history alone exceeds the context budget.\");\n\t\t\t\t} else {\n\t\t\t\t\tconst shape = snapcompactShape;\n\t\t\t\t\tif (!shape) {\n\t\t\t\t\t\tthrow new Error(\"snapcompact shape was not resolved before rendering.\");\n\t\t\t\t\t}\n\t\t\t\t\tsnapcompactResult = await snapcompact.compact(preparation, {\n\t\t\t\t\t\tconvertToLlm,\n\t\t\t\t\t\tmodel: this.#model,\n\t\t\t\t\t\t...(snapcompactShapeSetting === \"auto\" ? {} : { shape }),\n\t\t\t\t\t\tmaxFrames,\n\t\t\t\t\t\tincludeThinking: snapcompactIncludeThinking,\n\t\t\t\t\t});\n\t\t\t\t\tconst framePayloadBytes = this.#snapcompactFramePayloadBytes(snapcompactResult);\n\t\t\t\t\tif (framePayloadBytes > snapcompact.FRAME_DATA_BYTES_BUDGET) {\n\t\t\t\t\t\tlogger.warn(\"Snapcompact exceeded the per-request frame payload budget\", {\n\t\t\t\t\t\t\tmodel: this.#model?.id,\n\t\t\t\t\t\t\tframePayloadBytes,\n\t\t\t\t\t\t\tbudget: snapcompact.FRAME_DATA_BYTES_BUDGET,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.#host.emitNotice(\n\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\"snapcompact produced too much standing image payload.\",","sourceCodeStart":900,"sourceCodeEnd":936,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/session/session-maintenance.ts#L900-L936","documentation":"An internal invariant error: snapcompact reached the rendering step (`snapcompact.compact`) but the pre-computed `snapcompactShape` is undefined. The shape (conversation layout: frames, dimensions, kept-message split) must be resolved before rendering; a null here means an earlier resolution step was skipped or failed silently. This indicates a bug or a mis-wired custom path, not user error.","triggerScenarios":"A code path invoking the snapcompact render step without first running shape resolution (the step that computes kept-history fit and frame layout); settings combinations that skip resolution (e.g. snapcompactShape resolution gated behind a branch that doesn't run); upgrades where resolution moved but a caller wasn't updated.","commonSituations":"Custom forks/patches to compaction flow; extension or SDK callers reimplementing the snapcompact pipeline and skipping a step; race where shape resolution was aborted (e.g. by the compaction abort controller) but rendering continued.","solutions":["Retry the compaction — if transient (abort during shape resolution), a fresh run should resolve the shape.","Ensure the full snapcompact pipeline (shape resolution, then compact) is used rather than calling the render step directly.","If reproducible on an unmodified install, report a bug with the settings and session characteristics."],"exampleFix":"// before\nconst result = await snapcompact.compact(preparation, { model }); // shape never resolved\n// after\nconst shape = snapcompact.resolveShape(preparation, { model });\nconst result = await snapcompact.compact(preparation, { model, shape });","handlingStrategy":"retry","validationCode":null,"typeGuard":"function shapeResolved(shape: SnapcompactShape | undefined): shape is SnapcompactShape {\n  return shape != null;\n}\nif (!shapeResolved(snapcompactShape)) throw new Error(\"resolve shape before rendering\");","tryCatchPattern":"try {\n  await session.compact({ mode: \"snapcompact\" });\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"shape was not resolved\")) {\n    await Bun.sleep(100);\n    return session.compact({ mode: \"snapcompact\" }); // transient abort during resolution\n  }\n  throw err;\n}","preventionTips":["Use the full built-in snapcompact pipeline; never call the render step directly.","Check compaction abort signals between shape resolution and rendering.","Report persistent occurrences on unmodified installs as a bug."],"tags":["compaction","snapcompact","invariant-violation","internal"],"backgroundTag":"unresolved-state-before-render","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}