Skip to content

Known issues and limitations

What does not work yet, what was never meant to, and what works differently on purpose. Three different things, kept apart — a deliberate trade-off listed as a bug makes a considered decision look like neglect.

Applies to the 0.0.24 release (rs-rich-cli 0.0.24, rs-rich 0.0.14, published 2026-11-03), reviewed against Python rich 15.0.0. Older entries name the release they were found in. Each entry links to its issue or report so you can check the status without waiting for this page to be updated.


Bugs

Things that should work and do not.

Narrow --json output is display output, not machine-readable JSON

Scope. Default builds match upstream: narrow output may wrap or crop inside an escape, and --width crops overlong JSON lines. The optional, off-by-default json-escape-safe Cargo feature avoids partial escapes when cropping and keeps escapes together when folding at widths that can fit them. See DIVERGENCES §22. Neither mode promises machine-readable output; use the original JSON with jq when every value must survive.

The recorder keeps fewer frames on macOS

rich record keeps every screen update the program finished, up to the tape's frame rate. On Linux a game recorded at Set Framerate 35 keeps about 30 frames a second; on CI's macOS runners the same recording kept 7 frames over 0.8 s, so its video plays in jumps. 0.0.22 splits a late read into the updates inside it, which did not fix macOS: its runners still kept 5 frames over 0.5 s. The cause there is not known yet, and the frame-rate test keeps its lower bound on Linux only until it is. Record games on Linux for now. Found in 0.0.20, still open in 0.0.24 (plan).

The differential fuzzer found it in 0.0.22: an ordered list item whose only content is an empty link, 2) [](), renders no row when the Markdown is fully justified, where rich 15.0.0 prints the item's number. With the default justify the output matches. The case is kept in scripts/fixtures/diff_rich_known.jsonl until it is fixed (#769).


Limitations

Things that are not implemented, and are not claimed to be.

Windows legacy console is not supported

rich assumes a VT-capable terminal. On Windows it enables virtual terminal processing; on a console that cannot do VT (very old cmd.exe), output will contain raw escape sequences.

Upstream falls back to the Win32 console API for these. The port will not: every supported Windows release has a VT-capable console, so this is a permanent divergence (DIVERGENCES §38, #12). Workaround: use Windows Terminal, or --no-color.

The local time zone on Windows follows TZ when it is set

rs-rich-interact's Zone::Local (and so DateTime::now_local, natural dates and intuiTUIve's calendars) asks Windows for the system's zone, unless TZ is set: then TZ wins, as it does for the C runtime. Windows has no zoneinfo database, so TZ must be a POSIX rule (CET-1CEST,M3.5.0,M10.5.0/3) or TZDIR must name a zoneinfo directory; a zone name alone, such as Europe/Berlin, is read as UTC. See Troubleshooting.

Chrome's DevTools port on Windows in rs-rich-embed

On Windows, the Chrome engine of rs-rich-embed's web view talks to Chrome over DevTools on a random port of 127.0.0.1, which other programs and users on the machine can reach while the view is open, and DevTools has no authentication. On Windows, use the Chrome engine on a machine you do not share. On Linux and macOS it uses a pipe instead and opens no port (since rs-rich-embed 0.0.4, 0.0.21). Windows keeps the port until a maintained crate can pass Chrome the pipe's two inheritable handles in one switch (why).

No Jupyter integration, and no Python-object inspection

jupyter.py and inspect/repr have no equivalent: they render live Python objects, which has no meaning in a Rust port. pretty and traceback are reimplemented Rust-natively instead — see Divergences.

SVG export is not self-contained offline

--export-svg references its font from a CDN. The HTML from --export-html is self-contained. If you need an offline SVG, embed the font yourself after export.

GIF interruption and export limitations

--gif-mode is ascii (the default, and the redirected/colorless fallback) or blocks; see the capability matrix. Since 0.0.11, --image-color and --image-dither also apply to GIF frames. Normal playback restores the cursor; Ctrl-C can leave it hidden. GIF export and Sixel playback are unsupported.

Redaction is experimental and best effort

rich_ext::redact, rich capture --redact and --redact-pattern, and rich inspect --redact mask what their detectors recognise: secret-named keys, bearer tokens, common token prefixes, AWS key ids, JWTs and URL passwords. They can miss a secret in a format they do not know. Read the output, and any SVG, HTML or cast file written from it, before sharing it, and report anything that gets through. rich env masking is best effort in the same way.

Viewers read a bounded amount

view, hex, unicode, inspect, capture and --theme-file stop at a fixed size (for example 8 MiB or 20,000 lines for source in view, 64 MiB per inspect document, 1 MiB of capture output), so an endless input ends instead of exhausting memory. Larger inputs are shown in part or refused; the caps are not configurable. See Limits.

Mermaid subgraphs are drawn without frames; DOT's limits

rs-rich-diagram 0.0.2 frames DOT cluster… subgraphs and honours rank=same where a layered drawing can (a group an edge runs within is dropped, with a note); other rank values are accepted with a note. Mermaid flowcharts do not pass their subgraphs on as clusters yet, so those are still drawn without frames, with a note. ER diagrams attach relationship edges to an entity's box, not to the column's row. Node ports, HTML-like labels, record shapes and several graphs in one file are refused with the construct and its line (rich dot exits 4). For Graphviz's full layout, use --dot-backend graphviz --export-svg with Graphviz installed. See Diagrams.

SVG export can squeeze CJK glyphs

SVG textLength uses character counts for some runs; wide CJK glyphs may overlap in the exported image. The same case reproduces in pinned Python Rich 15.0.0. Decoded text and plain terminal output retain the original characters. This is an export-layout limitation, separate from encoding support.

CSV output still retains source rows

Undecorated CSV output streams styled rows, reducing output-buffer overhead. 0.0.4 removes duplicate parsed-cell storage and trims row capacity, reducing the measured 100k-row peak RSS by about 46%. Source rows remain in memory for measurement, so memory still scales with input. Decorated, aligned, paged and exported CSV output still buffers. The 0.0.4 work in #74 reduces retained memory; it does not provide bounded-memory processing.

Long-line rendering still allocates memory

0.0.4 removes repeated UTF-8 prefix scans during Text wrapping. On the recorded Linux benchmark, the 5 MiB Markdown paragraph now finishes in 531 ms; it previously timed out after 10 seconds. Source and rendered lines still occupy memory. See measured results for input-path distinctions, output verification and reproducible samples.

Headerless text encodings must be selected explicitly

0.0.4 supports --encoding utf-16, utf-16le, utf-16be and utf-8. Default files retain UTF-8 replacement decoding; stdin and URLs remain strict UTF-8. A recognized UTF-16 BOM gets an actionable hint. Headerless UTF-16 is not guessed: select its byte order explicitly or convert to UTF-8. See encoding troubleshooting.

Syntax parsing remains costly for varied source

The off-by-default 0.0.4 syntax-cache Cargo feature helps repeated boilerplate whose parser state stays unchanged. The off-by-default onig feature (0.0.11) makes all highlighting 2–4× faster by using Oniguruma, at the cost of a C build dependency. Default builds use uncached Syntect. Measured real-source files showed essentially unchanged runtime; loading and parsing new syntax still costs more than plain text. See the workload-specific results. Historical 0.0.2 Windows/Python comparisons are retained separately in the benchmark page; they are not current 0.0.4 measurements. The implemented scope of #45 is repeated-line parsing reuse, not a blanket syntax speedup.


Deliberate divergences

Things that work differently on purpose. The full list, each with its reasoning, is in Divergences; these are the ones you are most likely to notice.

Highlighted code does not match Python byte-for-byte

Upstream uses Pygments; this port uses syntect, which ships different grammars and themes. Colours therefore differ. Everything around the code — width, padding, wrapping, the background block — is parity-tested.

Replacing syntect would mean shipping a Pygments-equivalent lexer set, which is out of scope. This is divergence #18.

Raw ESC in input reaches the terminal in the upstream modes

In the modes ported from upstream (rich FILE, --print, --markdown, --json, …), an escape character in a rendered file is passed through, exactly as upstream passes it through. It is listed here because it surprises people, not because it is a defect: matching upstream is the project's whole purpose. BEL, backspace, vertical tab and form feed are stripped, as upstream strips them.

For untrusted input, pass --sanitize (since 0.0.5, #64), which shows terminal controls as inert symbols. rich view and text rich diff, which have no upstream behaviour to keep, sanitise by default; --no-sanitize turns that off. See Neutralize terminal controls.

Upstream tags OSC 8 hyperlinks with a random id derived from Python's RNG. Reproducing the byte sequence would mean reproducing the RNG, so ours omits it. Terminals do not depend on it. Divergence #20.


Fixed recently

Kept here so anyone on an older build still finds the symptom. Problems found and fixed in features that were never published (such as the 0.0.11 release-test fixes to view, stack traces and hyperlinks) are in the changelog instead. Full detail in the changelog.

Symptom Fixed in
rich plugin install, rich <url> and the marketplace statistics failed behind a TLS-inspecting proxy with invalid peer certificate: UnknownIssuer, or with chunk length cannot be read as a number on a redirect marketplace 0.0.2, CLI 0.0.23
--theme-style repr.number=bold printed numbers bold cyan, and a theme's markdown.* styles did not reach rich -m core 0.0.13, CLI 0.0.23
AnsiDecoder panicked on a multi-byte character after ESC ( core 0.0.13
A WASM plugin looping over memory.grow could abort the host in an optimised build; a module with an empty code section made it divide by zero ext 0.0.20
U+9FBC to U+9FFF measured two cells in rs-rich-ext's quick widths, where rich's tables before Unicode 5.2 measure one ext 0.0.20
A page switch showed a hidden page's last frame when it came back (Noctiluca's page area after opening a page in reader mode) intuituive 0.0.8
A session's process could slip past rich serve --memory on Linux during a large allocation at startup web 0.0.6
Noctiluca lost the text of pages laid out with nested tables, drew footers at the top, read The Guardian as one live log, panicked in find after a non-ASCII character, and drew AVIF pictures' alt text twice noctiluca 0.0.2
A recording of a video kept a frame mid synchronized update, showing half blocks over the last picture record 0.0.11, CLI 0.0.23
The Python package's console was a column wider than upstream's on a legacy Windows console with LINES set PyPI 0.0.11
A cx.focus(x) just before cx.modal(..) was lost when the modal closed; a styled layers node let the layers below show through its children's gaps; layout::squarify gave the largest item no tile; a previews_keys container took a command line's letters (round 7's four bugs) intuituive 0.0.6
Filtering a million rows through view_of was slower than a hand-written loop (15.4 s against 3.3 s unoptimised) intuituive 0.0.6, ext 0.0.18
Markdown the differential fuzzer and the parity work checked (tables nested in lists and quotes, tables that interrupt a paragraph, refused reference definitions, empty list items, empty link destinations) printed unlike upstream core 0.0.12
rs-rich-embed's Chrome engine sometimes ended when DevTools refused a history request during a navigation embed 0.0.5
A tape without Output also wrote an APNG; it is now written only when Output or --format names it record 0.0.10, CLI 0.0.22
A held key in a tape sent extra repeats after its release on a slow machine record 0.0.9, CLI 0.0.21
rich mermaid and rich_mermaid::Mermaid printed a blank line after the diagram mermaid 0.0.4, CLI 0.0.15
rich micro preview labelled a still image with a frame time ("100 ms") CLI 0.0.15
NO_COLOR also dropped bold and underline in a terminal core 0.0.7
A project rich.toml with no_color = false undid NO_COLOR CLI 0.0.11
Markup in plain-string table cells and tree labels printed literally core 0.0.7
Columns and Tree overflowed narrow widths core 0.0.7
--export-svg titled literal print text and rules with a fragment of the markup CLI 0.0.11
A multi-file --watch --watch-exit-on-error promised a retry it never made CLI 0.0.10
Live print dropped ordinary writes at widths 0 and 1; diagnostic snippets kept CRLF carriage returns ext 0.0.7
--watch missed same-size edits and atomic saves CLI 0.0.7
Diff exports lost graphical content when stdout was redirected 0.0.3
Notebook layout flags were ignored; title markup printed literally 0.0.3
Windows default pager failed to launch more.com 0.0.3
Redirected GIFs emitted cursor controls or looped forever 0.0.3
JSON rejected deep/non-finite input or rounded large integers 0.0.3
Early-closing CSV consumers produced an error 0.0.3
--csv printed a made-up one-column table and exited 0 on unreadable input 0.0.2 (round 9)
Markdown link destinations vanished from piped output 0.0.2 (round 9)
--syntax deleted every blank line in the file 0.0.2 (round 8)
Long lines in Markdown code blocks were cropped and their tail lost 0.0.2 (round 8)
Emoji and Indic text broke table and panel borders 0.0.2 (rounds 8–9)
Deeply nested Markdown crashed the process 0.0.2 (round 6)

Reporting something not listed here

Please open an issue with the exact command, the input if you can share it, and what you expected. If it is a parity difference from Python rich, Reporting a parity bug explains what makes those reports useful.