can1357/oh-my-pi · error
Failed to parse SSH config file ${filePath}: ${error.message
Error message
Failed to parse SSH config file ${filePath}: ${error.message} What it means
readSSHConfigFile parses an SSH config file (user ~/.ssh/config or project config) and wraps parse failures. When the parser raises a SyntaxError (malformed SSH config syntax), it is rethrown with the file path and underlying message prefixed, so the developer knows which config file is broken. ENOENT is treated as an empty config; all other errors propagate unchanged.
Source
Thrown at packages/coding-agent/src/ssh/config-writer.ts:38
hosts?: Record<string, SSHHostConfig>;
}
/**
* Read an SSH config file.
* Returns empty config if file doesn't exist.
*/
export async function readSSHConfigFile(filePath: string): Promise<SSHConfigFile> {
try {
const content = await fs.promises.readFile(filePath, "utf-8");
const parsed = JSON.parse(content) as SSHConfigFile;
return parsed;
} catch (error) {
if (isEnoent(error)) {
// File doesn't exist, return empty config
return { hosts: {} };
}
if (error instanceof SyntaxError) {
throw new Error(`Failed to parse SSH config file ${filePath}: ${error.message}`);
}
throw error;
}
}
/**
* Write an SSH config file atomically.
* Creates parent directories if they don't exist.
*/
export async function writeSSHConfigFile(filePath: string, config: SSHConfigFile): Promise<void> {
// Ensure parent directory exists
const dir = path.dirname(filePath);
await fs.promises.mkdir(dir, { recursive: true, mode: 0o700 });
// Write to temp file first (atomic write)
const tmpPath = `${filePath}.tmp`;
const content = JSON.stringify(config, null, 2);
await fs.promises.writeFile(tmpPath, content, { encoding: "utf-8", mode: 0o600 });View on GitHub (pinned to 9690622007)
Solutions
- Open the file at the reported path and fix the syntax error indicated by error.message
- Validate the file with `ssh -G <host>` or run ssh against it to locate offending lines
- Restore the file from backup or version control
- If the file is unrecoverable, move it aside and let the tooling write a fresh config
Example fix
# before (bad config) Host work HostName # after Host work HostName ssh.example.com
Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
try {
const cfg = await readSSHConfigFile(filePath);
} catch (err) {
if (err instanceof Error && err.message.startsWith("Failed to parse SSH config file")) {
// surface path, prompt user to fix or restore the config
} else throw err;
} Prevention
- Validate ~/.ssh/config with `ssh -G` after hand edits
- Keep configs in version control for easy restore
- Avoid pointing the tool at generated/partial config files
When it happens
Trigger: Calling readSSHConfigFile (directly or via addSSHHost/updateSSHHost/removeSSHHost, or reading user/project config) on a file with invalid SSH config syntax — unterminated patterns, garbage characters, invalid structures the parser rejects.
Common situations: Hand-edited ~/.ssh/config with typos, files generated by other tools in a format the parser doesn't accept, truncated files from interrupted writes, or non-UTF8/binary content in the config path.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- imageUrls exposure "ssh" requires imageUrls.publicBaseUrl
- imageUrls exposure "ssh" requires imageUrls.sshTarget
- ssh reverse forward to ${config.sshTarget} exited with code
- SFTP password injection is unsupported by the shared SSH tra
- No known OAuth callback port for '${provider}'. Use device-c
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/78c5fb70d5b04337.
Report an issue: GitHub.