Hmbown/CodeWhale · error · RegistryError
invalid_user
invalid_user
Error message
user must be a plain name
What it means
RegistryError "invalid_user": for ssh transports, an optional rest.user must match ^[a-zA-Z0-9._-]+$ — a plain login name. The user string is interpolated into an ssh command line, so values containing spaces, @, /, or shell metacharacters are rejected to prevent argument injection and broken ssh invocations.
Solutions
- Use only the bare login name, e.g. user: "alice".
- Strip domain prefixes/backslashes and everything after @ or space before registering.
- Omit rest.user entirely to rely on the machine's default ssh identity/ssh-config user.
- Escape or sanitize any programmatically derived user value against ^[a-zA-Z0-9._-]+$.
Example fix
// before
register({ id: "lab", transport: "ssh", host: "10.0.0.5", user: "alice@example.com" });
// after
register({ id: "lab", transport: "ssh", host: "10.0.0.5", user: "alice" }); Defensive patterns
Strategy: validation
Validate before calling
const USER_RE = /^[a-zA-Z0-9._-]+$/;
if (user != null && (typeof user !== "string" || !USER_RE.test(user))) throw new Error("user must be a plain login name"); Type guard
const isPlainUser = (u) => typeof u === "string" && /^[a-zA-Z0-9._-]+$/.test(u);
Try / catch
try {
register(cfg);
} catch (e) {
if (e?.code === "invalid_user") throw new Error(`User "${cfg.user}" rejected; use the bare login name`);
throw e;
} Prevention
- Strip domain prefixes (DOMAIN\\user) and @realm suffixes
- Omit user to use ssh's default identity
- Never pass shell-quoted or spaced identities
- Treat user as an opaque plain token, not a connection string
When it happens
Trigger: register({ id: "x", transport: "ssh", host: "h", user: "alice dev" }); user: "alice; rm -rf /"; user: "domain\\alice"; user: "" (empty string fails the regex).
Common situations: Copy-pasting a full identity like "alice@example.com" or "DOMAIN\\alice" from Windows environments; accidentally leaving an empty user key from a template; shell-quoted strings from scripts.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/1588f95e0e2776f7.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/registry.mjs:94
/** Register or update a computer. Returns the entry. */
export function register({ id, transport, label, ...rest }) {
if (!id || !ID_RE.test(id)) throw new RegistryError("invalid_id", "computer id must match " + ID_RE);
if (!["local", "ssh", "hdc", "docker"].includes(transport)) {
throw new RegistryError("invalid_transport", "transport must be one of: local, ssh, hdc, docker");
}
if (id === "local" && transport !== "local") {
throw new RegistryError("reserved_id", '"local" is reserved for this machine');
}
if (transport === "ssh") {
if (!rest.host || !/^[A-Za-z0-9._-]+$/.test(rest.host)) {
throw new RegistryError("invalid_host", "ssh computers need a valid host (letters, digits, dot, dash, underscore)");
}
if (rest.port != null && (!Number.isInteger(rest.port) || rest.port < 1 || rest.port > 65535)) {
throw new RegistryError("invalid_port", "port must be an integer in 1..65535");
}
if (rest.user != null && !/^[a-zA-Z0-9._-]+$/.test(rest.user)) {
throw new RegistryError("invalid_user", "user must be a plain name");
}
}
if (transport === "hdc") {
if (rest.target != null && !/^[A-Za-z0-9._-]*$/.test(rest.target)) {
throw new RegistryError("invalid_target", "hdc target key contains invalid characters");
}
rest.platform = "harmonyos";
}
if (transport === "docker") {
if (!rest.container || !/^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$/.test(rest.container)) {
throw new RegistryError("invalid_container", "docker computers need a valid container name");
}
// Spawned containers always run the Linux desktop image.
rest.platform = rest.platform ?? "linux";
}
const reg = load();
const prev = reg.computers[id];
reg.computers[id] = {View on GitHub (pinned to 73e0f67d83)