can1357/oh-my-pi · error · ValidationError

${name} path does not exist: ${trimmed}

Error message

${name} path does not exist: ${trimmed}

What it means

resolvePemValue accepts a TLS/SSH key material either inline (a PEM string containing '-----BEGIN') or as a file path. When the value looks like a path (contains / or \ or ends in .pem/.crt/.cer/.key) but reading it fails with ENOENT, the library throws a ValidationError naming the parameter and the path. This is a configuration error: the caller pointed a cert/key option at a file that does not exist.

Source

Thrown at packages/ai/src/providers/anthropic.ts:1300

function looksLikeFilePath(value: string): boolean {
	return value.includes("/") || value.includes("\\") || /\.(pem|crt|cer|key)$/i.test(value);
}

function resolvePemValue(value: string | undefined, name: string): string | undefined {
	const trimmed = value?.trim();
	if (!trimmed) return undefined;

	const inline = trimmed.replace(/\\n/g, "\n");
	if (inline.includes("-----BEGIN")) {
		return inline;
	}

	if (looksLikeFilePath(trimmed)) {
		try {
			return fs.readFileSync(trimmed, "utf8");
		} catch (error) {
			if (isEnoent(error)) {
				throw new AIError.ValidationError(`${name} path does not exist: ${trimmed}`);
			}
			throw error;
		}
	}

	return inline;
}

function resolveFoundryTlsOptions(model: Model<"anthropic-messages">): FoundryTlsOptions | undefined {
	if (model.provider !== "anthropic") return undefined;
	if (!isFoundryEnabled()) return undefined;

	const cacheKey = foundryTlsOptionsCacheKey();
	if (foundryTlsOptionsCache.has(cacheKey)) return foundryTlsOptionsCache.get(cacheKey);

	const ca = resolvePemValue($env.NODE_EXTRA_CA_CERTS, "NODE_EXTRA_CA_CERTS");
	const cert = resolvePemValue($env.CLAUDE_CODE_CLIENT_CERT, "CLAUDE_CODE_CLIENT_CERT");
	const key = resolvePemValue($env.CLAUDE_CODE_CLIENT_KEY, "CLAUDE_CODE_CLIENT_KEY");

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the file exists at the exact path given (ls the path with the same user/working directory the app runs as)
  2. Use absolute paths in configuration so the app's CWD cannot change resolution
  3. If embedding the key inline, ensure it contains the full '-----BEGIN ... PRIVATE KEY-----' header and real newlines (or literal \n escapes)
  4. In containers, confirm the secret mount and volume mountPath match the configured path
  5. Catch this ValidationError at startup and fail fast with a clear config-error message instead of at first request

Example fix

// before: relative path, breaks when CWD changes
tls: { keyFile: "certs/client-key.pem" }
// after: absolute path + existence check at boot
const keyPath = path.resolve(process.env.KEY_DIR ?? "/etc/app/certs", "client-key.pem");
if (!fs.existsSync(keyPath)) throw new Error(`Missing TLS key: ${keyPath}`);
tls: { keyFile: keyPath }
Defensive patterns

Strategy: validation

Validate before calling

import * as fs from "node:fs";
function assertPemReadable(name: string, value: string | undefined): void {
  const trimmed = value?.trim();
  if (!trimmed) return;
  if (trimmed.includes("-----BEGIN")) return;
  if (trimmed.includes("/") || trimmed.includes("\\") || /\.(pem|crt|cer|key)$/i.test(trimmed)) {
    if (!fs.existsSync(trimmed)) throw new Error(`${name} path does not exist: ${trimmed}`);
  }
}

Type guard

function isPemMaterial(value: string): boolean {
  return value.includes("-----BEGIN");
}

Try / catch

try {
  await createProvider(opts);
} catch (err) {
  if (err instanceof AIError.ValidationError && err.message.includes("path does not exist")) {
    // config error: cert/key file missing; fail fast with actionable guidance
    throw new Error(`TLS config error — ${err.message}. Check secret mounts and use absolute paths.`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Passing a path to a PEM option (client certificate/key, CA bundle for Foundry TLS, mTLS settings) where the file is missing — wrong relative path, file deleted, secret not mounted in the container, or an inline key whose newlines were mangled so it no longer contains '-----BEGIN' and is therefore treated as a path.

Common situations: Kubernetes/containers where the secret volume wasn't mounted at the expected path; env vars set with escaped \n that collapsed incorrectly; running from a different working directory so relative paths break; copying config between machines where cert files live elsewhere.

Related errors


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