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
- Use unit='chars' (the default) or unit='lines'
- For finer granularity, call search() with a regex and work with the returned snippets
- When generating code for this REPL, treat the error text as the closed vocabulary and retry with a supported unit
- 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
- Whitelist units through a normalize helper before every peek call
- Enumerate supported units in prompts that generate REPL code
- Use search() with a regex for sub-line granularity
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
- max_chars must be > 0
- overlap must be smaller than max_chars
- version must be a semantic release identifier
- max_turns must be between 1 and 10000
- disabled_tools must use Codewhale catalog identifiers: ${",
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/4562a73727ab600c.
Report an issue: GitHub.