{"record":{"id":"f948564e0e900629","repo":"can1357/oh-my-pi","slug":"ssh-remotepath-is-a-binary-or-non-utf-8-fil","errorCode":null,"errorMessage":"ssh://: ${remotePath} is a binary or non-UTF-8 file; ssh:// supports UTF-8 text only — use `bash` with a remote SSH command or an `sshfs` mount","messagePattern":"ssh://: (.+?) is a binary or non-UTF-8 file; ssh:// supports UTF-8 text only — use `bash` with a remote SSH command or an `sshfs` mount","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/internal-urls/ssh-protocol.ts","lineNumber":306,"sourceCode":"\t\t\treturn this.#resolveDirectory(target, remotePath, url, context?.signal, context?.skipDirectoryListing);\n\t\t}\n\t\tif (kind === \"other\") {\n\t\t\tthrow new Error(\n\t\t\t\t`ssh://: ${remotePath} is not a regular file (FIFO, socket, or device); ssh:// reads UTF-8 text files only — use \\`bash\\` with a remote SSH command for special files`,\n\t\t\t);\n\t\t}\n\t\tconst fileResult = await readRemoteFile(target, remotePath, {\n\t\t\tmaxBytes: SSH_TEXT_MAX_BYTES,\n\t\t\tsignal: context?.signal,\n\t\t});\n\t\tif (fileResult.truncated) {\n\t\t\tthrow new Error(\n\t\t\t\t`ssh://: ${remotePath} exceeds the 1 MiB limit; ssh:// supports text files up to 1 MiB — use an sshfs mount for larger files`,\n\t\t\t);\n\t\t}\n\t\tconst content = decodeUtf8Text(fileResult.bytes);\n\t\tif (content === null) {\n\t\t\tthrow new Error(\n\t\t\t\t`ssh://: ${remotePath} is a binary or non-UTF-8 file; ssh:// supports UTF-8 text only — use \\`bash\\` with a remote SSH command or an \\`sshfs\\` mount`,\n\t\t\t);\n\t\t}\n\t\t// No `sourcePath`: keeps search on the virtual-resource path so the\n\t\t// displayed/searched resource stays `ssh://…` instead of a temp path.\n\t\treturn {\n\t\t\turl: url.href,\n\t\t\tcontent,\n\t\t\tcontentType: contentTypeFor(remotePath),\n\t\t\tsize: fileResult.bytes.length,\n\t\t};\n\t}\n\n\t/** Resolve a remote directory to a one-level listing (no `sourcePath`; `isDirectory` so search refuses it; immutable). */\n\tasync #resolveDirectory(\n\t\ttarget: SSHConnectionTarget,\n\t\tremotePath: string,\n\t\turl: InternalUrl,","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/internal-urls/ssh-protocol.ts#L288-L324","documentation":"After a successful bounded read, the bytes are decoded with a fatal UTF-8 decoder that also rejects any NUL byte. If decoding fails, the file is binary or non-UTF-8 (e.g. Latin-1, images, executables), which ssh:// does not support — it only returns UTF-8 text.","triggerScenarios":"Resolving an ssh:// URL to a file whose bytes contain invalid UTF-8 sequences or a NUL byte, so `decodeUtf8Text` returns null — e.g. `ssh://prod/usr/bin/tool` or a Latin-1-encoded text file.","commonSituations":"Pointing ssh:// at executables, images, archives; legacy text files in non-UTF-8 encodings (Windows-1252, ISO-8859-1, Shift-JIS); files with a stray NUL from corruption.","solutions":["Re-encode the file remotely to UTF-8 (e.g. `iconv -f latin1 -t utf-8`) and read the result","Use the bash tool for binary inspection: `ssh prod 'xxd file | head'`, checksums, `file` output","Mount via sshfs and use binary-capable local tooling","Repair/re-download the file if the NUL indicates corruption"],"exampleFix":"// before\nresolve('ssh://prod/data/legacy-iso8859.txt')\n// after\nbash(\"ssh prod 'iconv -f iso-8859-1 -t utf-8 /data/legacy.txt > /tmp/legacy-utf8.txt'\")\nresolve('ssh://prod/tmp/legacy-utf8.txt')","handlingStrategy":"try-catch","validationCode":"const head = await bash(`ssh ${host} head -c 4096 ${remotePath} | file -`);\nif (!head.includes('text')) throw new Error(`${remotePath} looks binary; use bash/sshfs`);","typeGuard":null,"tryCatchPattern":"try {\n  const res = await handler.resolve(url, ctx);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('binary or non-UTF-8 file')) {\n    // inspect via bash (xxd/file) or iconv-convert to UTF-8 first\n  } else throw e;\n}","preventionTips":["Verify remote files are UTF-8 text (`file -bi`) before reading via ssh://","Convert legacy encodings with iconv on the remote before reading","Never use ssh:// for executables, images, or archives — use bash or sshfs"],"tags":["ssh","encoding","binary-file"],"backgroundTag":"non-utf8-file-content","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}