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

  1. Open the file at the reported path and fix the syntax error indicated by error.message
  2. Validate the file with `ssh -G <host>` or run ssh against it to locate offending lines
  3. Restore the file from backup or version control
  4. 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

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

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/78c5fb70d5b04337. Report an issue: GitHub.