sxyazi/yazi · error
The cursor position is out of bounds.
Error message
The cursor position is out of bounds.
What it means
The `shell` action form validates the optional `cursor` field: if set, it must be ≤ the character count of the command string (`run`). A larger value means the caret would sit past the end of the input, so construction bails with this error.
Source
Thrown at yazi-parser/src/mgr/shell.rs:30
#[serde(default)]
pub block: bool,
#[serde(default)]
pub orphan: bool,
#[serde(default)]
pub interactive: bool,
pub cursor: Option<usize>,
}
impl TryFrom<ActionCow> for ShellForm {
type Error = anyhow::Error;
fn try_from(a: ActionCow) -> Result<Self, Self::Error> {
let me: Self = a.deserialize()?;
if me.cursor.is_some_and(|c| c > me.run.chars().count()) {
bail!("The cursor position is out of bounds.");
}
Ok(me)
}
}
impl FromLua for ShellForm {
fn from_lua(_: Value, _: &Lua) -> mlua::Result<Self> { Err("unsupported".into_lua_err()) }
}
impl IntoLua for ShellForm {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}
View on GitHub (pinned to 5f901b886b)
Solutions
- Clamp cursor to `run.chars().count()` before emitting the action.
- Omit cursor (None) to let the shell action default the position.
- Compute the cursor with the same char semantics (`chars().count()` / Lua `#` on chars) used by the validator, not byte length.
Example fix
// before let cursor = Some(old_pos); ShellForm::from_action(run, cursor) // after let n = run.chars().count(); let cursor = Some(old_pos.min(n));
Defensive patterns
Strategy: validation
Validate before calling
assert!(cursor.map_or(true, |c| c <= run.chars().count()),
"cursor must be <= run.chars().count()"); Type guard
fn is_valid_cursor(run: &str, cursor: Option<usize>) -> bool {
cursor.map_or(true, |c| c <= run.chars().count())
} Try / catch
match ShellForm::try_from(action) {
Ok(form) => open(form),
Err(e) if e.to_string().contains("cursor position is out of bounds") => {
eprintln!("cursor beyond end of command: {e}")
}
Err(e) => return Err(e),
} Prevention
- Clamp stored cursors whenever the command text shrinks.
- Count characters (chars().count()), never bytes, when computing cursor positions.
- Prefer omitting the cursor field unless you track it accurately.
When it happens
Trigger: Emitting the `mgr:shell` action with a `cursor` value greater than the number of chars in `run` — e.g. `run = "ls"` with `cursor = 5`, or a stale cursor carried over from a longer previous command.
Common situations: Plugin state that remembers the caret position but updates the command to a shorter string; byte-vs-char confusion with multibyte commands (validation counts chars, not bytes); hand-built keymap bindings with hardcoded cursors.
Related errors
- Invalid 'summary' in UpdateProgressForm
- Invalid 'cfg' in ShowForm
- Invalid 'token' in ShowForm
- Linemode must be between 1 and 20 characters long
AI-assisted analysis of sxyazi/yazi@5f901b886b (2026-09-02).
Data as JSON: /api/errors/0471bcde772058d8.
Report an issue: GitHub.