{"record":{"id":"95e7567b4197f4ce","repo":"can1357/oh-my-pi","slug":"snapcompact-cannot-render-this-conversation-locall","errorCode":null,"errorMessage":"snapcompact cannot render this conversation locally: unsupported characters for selected snapcompact font (${percent}%).","messagePattern":"snapcompact cannot render this conversation locally: unsupported characters for selected snapcompact font \\((.+?)%\\)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/session/session-maintenance.ts","lineNumber":885,"sourceCode":"\t\t\t\tconst text = snapcompact.serializeConversation(\n\t\t\t\t\tconvertToLlm(preparation.messagesToSummarize.concat(preparation.turnPrefixMessages)),\n\t\t\t\t\t{ includeThinking: snapcompactIncludeThinking },\n\t\t\t\t);\n\t\t\t\tconst probeText = snapcompact.renderabilityProbeText(\n\t\t\t\t\ttext,\n\t\t\t\t\tpreparation.previousPreserveData,\n\t\t\t\t\tpreparation.previousSummary,\n\t\t\t\t);\n\t\t\t\tsnapcompactShape = snapcompact.resolveShapeForText(probeText, this.#model, snapcompactShapeSetting);\n\t\t\t\tconst renderScan = snapcompact.scanRenderability(probeText, { shape: snapcompactShape });\n\t\t\t\tif (!renderScan.isSafe) {\n\t\t\t\t\tconst percent = (renderScan.unrenderableRatio * 100).toFixed(1);\n\t\t\t\t\tthis.#host.emitNotice(\n\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t`snapcompact disabled: unsupported characters for selected snapcompact font (${percent}%).`,\n\t\t\t\t\t\t\"compaction\",\n\t\t\t\t\t);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`snapcompact cannot render this conversation locally: unsupported characters for selected snapcompact font (${percent}%).`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet summary: string;\n\t\t\tlet shortSummary: string | undefined;\n\t\t\tlet firstKeptEntryId: string;\n\t\t\tlet tokensBefore: number;\n\t\t\tlet details: unknown;\n\t\t\tlet codexCompaction: CodexCompactionContext | undefined;\n\n\t\t\t// Snapcompact runs locally first. The frame cap is sized from the live\n\t\t\t// model window via #computeSnapcompactMaxFrames so the post-render context\n\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) {","sourceCodeStart":867,"sourceCodeEnd":903,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/session/session-maintenance.ts#L867-L903","documentation":"Thrown when snapcompact's renderability probe finds too large a fraction of the conversation text cannot be rendered by the selected snapcompact bitmap font (unrenderable ratio above the configured limit). Because unrenderable characters would corrupt or blank out archived history images, snapcompact refuses to run rather than silently lose content. A warning notice with the exact percentage is emitted first.","triggerScenarios":"Running snapcompact on a conversation dense in characters outside the snapcompact font's coverage — CJK/emoji/heavy non-Latin text, unusual box-drawing/control characters in tool output, or a custom `compaction.snapcompactFont` setting with narrow glyph coverage.","commonSituations":"Sessions working mostly in Chinese/Japanese/Korean or with emoji-heavy logs; code reading binary-ish data printed into the transcript; a font setting changed/removed in an upgrade leaving a font that can't cover the session's script.","solutions":["Configure a snapcompact font with wider glyph coverage for your content (compaction snapcompact settings).","Fall back to a text summarization mode: `/compact soft` or `/compact remote`.","Reduce non-renderable content (strip emoji/control chars from tool output) if you must use snapcompact."],"exampleFix":"// before\nawait session.compact({ mode: \"snapcompact\" }); // CJK-heavy session\n// after\nawait session.compact({ mode: \"soft\" }); // or set a CJK-capable snapcompact font","handlingStrategy":"fallback","validationCode":"const probe = snapcompact.renderabilityProbeText(conversationText);\nconst ratio = snapcompact.unrenderableRatio(probe, font);\nif (ratio > 0.05) useSnapcompact = false; // >5% unrenderable — use text summary","typeGuard":null,"tryCatchPattern":"try {\n  await session.compact({ mode: \"snapcompact\" });\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"unsupported characters\")) {\n    return session.compact({ mode: \"soft\" });\n  }\n  throw err;\n}","preventionTips":["Select a snapcompact font covering the scripts your sessions use (CJK, emoji).","Probe renderability on a sample before enabling snapcompact by default.","Strip emoji/control characters from tool output that flows into the transcript."],"tags":["compaction","snapcompact","rendering","unicode"],"backgroundTag":"unsupported-characters-for-font","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}