Hmbown/CodeWhale · error · ValueError

unit must be 'chars' or 'lines'

Error message

unit must be 'chars' or 'lines'

What it means

Raised by peek(start, end, unit) inside the Python REPL the Codewhale TUI embeds (crates/tui/src/repl/runtime.rs) for model-generated code operating on the loaded input _context. The unit argument accepts only 'char'/'chars' or 'line'/'lines' after str().lower(); anything else raises ValueError before any slicing happens. It guards the bounded slicer against requests for units it cannot serve, such as words or tokens.

Source

Thrown at crates/tui/src/repl/runtime.rs:865

def _slice_chars(start, end):
    total = len(_context)
    s = max(0, int(start))
    e = max(s, min(total, int(end)))
    return _context[s:e]

def _slice_lines(start, end):
    lines = _context.splitlines()
    s = max(0, int(start))
    e = max(s, min(len(lines), int(end)))
    return "\n".join(lines[s:e])

def peek(start, end, unit="chars"):
    """Return a bounded slice of the input by char offsets or line numbers."""
    if str(unit).lower() in ("line", "lines"):
        return _slice_lines(start, end)
    if str(unit).lower() not in ("char", "chars"):
        raise ValueError("unit must be 'chars' or 'lines'")
    return _slice_chars(start, end)

def search(pattern, max_hits=100):
    """Regex-search the input and return bounded hit records with snippets."""
    max_hits = max(0, int(max_hits))
    hits = []
    if max_hits == 0:
        return hits
    rx = _re.compile(str(pattern), _re.MULTILINE)
    for i, m in enumerate(rx.finditer(_context)):
        if i >= max_hits:
            break
        start, end = m.span()
        snippet_start = max(0, start - 120)
        snippet_end = min(len(_context), end + 120)
        hits.append({
            "index": i,
            "start": start,

View on GitHub (pinned to 8880682c63)

Solutions

  1. Use unit='chars' (the default) or unit='lines'
  2. For finer granularity, call search() with a regex and work with the returned snippets
  3. When generating code for this REPL, treat the error text as the closed vocabulary and retry with a supported unit
  4. For word-level access, slice lines yourself: peek(0, n, 'lines').split()

Example fix

# before
peek(0, 40, 'words')
# after
peek(0, 40, 'chars')  # or peek(0, 5, 'lines')
Defensive patterns

Strategy: type-guard

Validate before calling

unit = 'lines' if want_line_numbers else 'chars'
text = peek(start, end, unit)

Type guard

def normalize_unit(u, default='chars'):
    u = str(u).lower()
    if u in ('line', 'lines'):
        return 'lines'
    if u in ('char', 'chars'):
        return 'chars'
    return default

text = peek(start, end, normalize_unit(unit))

Try / catch

try:
    text = peek(start, end, unit)
except ValueError:
    text = peek(start, end, 'chars')

Prevention

When it happens

Trigger: Model-generated REPL code calling peek(0, 200, 'words'), peek(0, 10, 'tokens'), peek(0, 3, 'sentences'), or passing a non-string like ['chars'] whose str() form no longer matches the closed set.

Common situations: LLMs assuming token-based offsets from other APIs; prompts instructing sentence-level peeks; code migrated from tools whose peek supports arbitrary units.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/4562a73727ab600c. Report an issue: GitHub.