zylon-ai/private-gpt · error · ValueError

Unknown text_editor command

Error message

Unknown text_editor command: {command!r}. Expected one of: {', '.join(_dispatch)}

What it means

ValueError raised at the top of the text_editor dispatch closure when the command argument has no entry in _dispatch, the dict of supported subcommands (view, str_replace, create, etc.). It exists to reject unsupported or misspelled commands before any session call, and its message enumerates the valid keys.

Solutions

  1. Use one of the commands listed in the error message (they mirror the _dispatch keys, e.g. view, str_replace, create).
  2. Tighten the tool schema/description sent to the model so command is constrained to the enum of supported values.
  3. Upgrade client and server to matching versions if a command legitimately exists on one side only.

Example fix

# before
await text_editor(command="write", path="/tmp/a.txt", file_text="hi")

# after
await text_editor(command="create", path="/tmp/a.txt", file_text="hi")
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED = {"view", "str_replace", "create"}  # keep in sync with _dispatch
if command not in ALLOWED:
    raise ValueError(f"command must be one of {sorted(ALLOWED)}")
await text_editor(command=command, path=path, **extra)

Type guard

def is_known_text_editor_command(cmd: str) -> bool:
    return isinstance(cmd, str) and cmd in {"view", "str_replace", "create"}

Try / catch

try:
    await text_editor(command=command, path=path)
except ValueError as e:
    if "Unknown text_editor command" in str(e):
        # re-prompt the model with the allowed command list
        pass
    raise

Prevention

When it happens

Trigger: Calling the combined text_editor tool with command='edit', 'write', 'replace' or any string not present in _dispatch; the lookup child = _dispatch.get(command) returns None and the f-string error is raised.

Common situations: LLM/agent invents a command name not in the tool schema; version skew where a client sends a command added in a newer/older version; case sensitivity ('View' vs 'view').

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/f03e2834be9149ed. Report an issue: GitHub.

Appendix: source

Thrown at private_gpt/components/tools/builders/text_editor_code_execution_tool_builder.py:79

            TEXT_EDITOR_VIEW_TOOL_NAME: view_tool,
            TEXT_EDITOR_STR_REPLACE_TOOL_NAME: str_replace_tool,
            TEXT_EDITOR_CREATE_TOOL_NAME: create_tool,
            TEXT_EDITOR_INSERT_TOOL_NAME: insert_tool,
        }

        async def text_editor(
            command: str,
            path: str,
            view_range: list[int] | None = None,
            old_str: str | None = None,
            new_str: str | None = None,
            file_text: str | None = None,
            insert_line: int | None = None,
            insert_text: str | None = None,
        ) -> list[ResultContentBlockType]:
            child = _dispatch.get(command)
            if child is None:
                raise ValueError(
                    f"Unknown text_editor command: {command!r}. "
                    f"Expected one of: {', '.join(_dispatch)}"
                )
            kwargs: dict[str, Any] = {"path": path}
            if command == TEXT_EDITOR_VIEW_TOOL_NAME:
                if view_range is not None:
                    kwargs["view_range"] = view_range
            elif command == TEXT_EDITOR_STR_REPLACE_TOOL_NAME:
                kwargs["old_str"] = old_str
                kwargs["new_str"] = new_str
            elif command == TEXT_EDITOR_CREATE_TOOL_NAME:
                kwargs["file_text"] = file_text
            elif command == TEXT_EDITOR_INSERT_TOOL_NAME:
                kwargs["insert_line"] = insert_line
                kwargs["new_str"] = insert_text if insert_text is not None else new_str
            return await child.async_fn(**kwargs)

        return ToolSpec.from_defaults(

View on GitHub (pinned to 4a030776a3)