Skip to content

Hyperlink arena exhaustion (StringAllocOutOfMemory) spins the write path instead of degrading #186

Description

@co-cy

Summary

When the terminal's hyperlink string arena is exhausted, the write path appears to spin / not make forward progress instead of dropping the hyperlink and continuing. Writing a large, OSC 8-dense buffer in one shot floods this warning and then pins the thread:

warning(terminal): error reallocating for more hyperlink space, ignoring hyperlink err=error.StringAllocOutOfMemory

The ignoring hyperlink wording suggests the intent is to degrade gracefully, but in practice the containing write does not return.

Environment

  • ghostty-web@^0.4.0, running as WASM in an Electron renderer (embedded by Nimbalyst).
  • Trigger: replaying a terminal's saved scrollback (~500 KB, very hyperlink-dense — Claude Code / Codex emit many OSC 8 clickable file paths) into the terminal in a single write on session restore.

Observed behavior

  • A burst of ~70 identical StringAllocOutOfMemory hyperlink warnings within ~7 ms, then silence.
  • The renderer's main thread then sits at ~100% of one core with 0 syscalls over a 6 s strace sample — i.e. a pure userspace loop, not I/O or a lock.
  • A paused JS stack shows the top frame inside the WASM invoke trampoline — control went into the terminal write and never came back.

So once the arena is full, processing the remaining OSC 8 sequences in that write seems to loop rather than skip-and-advance.

Question / hypothesis

  • Is hyperlink-arena exhaustion expected to be recoverable within a single terminal.write? It looks like the post-failure "ignoring hyperlink" path may retry the allocation (or fail to advance the parser) when the arena stays full for the next hyperlink in the same write, turning many consecutive OSC 8 sequences into an unbounded loop.
  • Could you point me to where StringAllocOutOfMemory from the hyperlink path is handled? If the fix is "drop the hyperlink, advance, and don't re-attempt until space frees", that would turn this from a hang into graceful degradation.

Caveats

I don't yet have a standalone ghostty-web reproduction — this was diagnosed through the Nimbalyst embedding (traces above). If a minimal repro would help, I can try to build one that writes a synthetic OSC 8-dense buffer larger than the arena in a single call; a pointer to the arena size / relevant source would speed that up.

Filing here since ghostty-web owns the WASM build; if this is upstream Ghostty behavior, happy to move it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions