can1357/oh-my-pi · error

Missing required destination credential: ${key}

Error message

Missing required destination credential: ${key}

What it means

requireCredential reads a destination credential and throws when it is missing or empty, without echoing the value in the message. Credentials (token, apiKey, webhook, authorization headers) are mandatory for destinations that authenticate, so the uploader refuses to run without one. The message deliberately names only the key to avoid leaking secrets.

Source

Thrown at packages/coding-agent/src/blob-broker/uploader-runtime.ts:87

/** Read a boolean option, returning a fallback when it is absent. */
export function optionBoolean(config: DestinationRuntimeConfig, key: string, fallback?: boolean): boolean | undefined {
	const value = config.options[key];
	if (value === undefined) return fallback;
	if (typeof value !== "boolean") throw new Error(`Destination option ${key} must be a boolean`);
	return value;
}

/** Read a credential without exposing its value in an error. */
export function credentialString(config: DestinationRuntimeConfig, key: string): string | undefined {
	const value = config.credentials[key];
	return value === "" ? undefined : value;
}

/** Read a required credential without exposing its value in an error. */
export function requireCredential(config: DestinationRuntimeConfig, key: string): string {
	const value = credentialString(config, key);
	if (value === undefined) throw new Error(`Missing required destination credential: ${key}`);
	return value;
}

/** Select the injected request implementation, or Bun's global fetch by default. */
export function fetchFor(config: DestinationRuntimeConfig): FetchImpl {
	return config.fetch ?? globalThis.fetch;
}

/** Produce a safe remote filename from an upload request. */
export function fileNameFor(request: BlobUploadRequest): string {
	const preferred = request.filename?.trim().replaceAll("\\", "/").split("/").pop();
	if (preferred && preferred !== "." && preferred !== "..") return preferred;
	const extension = request.extension.replace(/^\.+/, "");
	return extension ? `upload.${extension}` : "upload";
}

/** Build a native multipart form containing string fields and the uploaded file. */
export function multipartFile(

View on GitHub (pinned to 9690622007)

Solutions

  1. Set the credential in the destination config: `{ "credentials": { "apiKey": "..." } }`.
  2. In CI, ensure the secret is injected (env var or secret manager) and mapped to the right credential key.
  3. Check the key name spelling against the destination's documented credential key.
  4. Verify the credential is non-empty — whitespace-only values may pass but an empty string fails.

Example fix

// before
{ "credentials": {} }
// after
{ "credentials": { "apiKey": process.env.UPLOAD_API_KEY } }
Defensive patterns

Strategy: try-catch

Validate before calling

const REQUIRED = ["apiKey"];
for (const key of REQUIRED) {
  const v = config.credentials[key];
  if (typeof v !== "string" || v.trim() === "") throw new Error(`credential ${key} is not set`);
}

Type guard

const hasCredential = (c: Record<string, unknown>, k: string): c is Record<string, string> => typeof c[k] === "string" && (c[k] as string).length > 0;

Try / catch

try {
  await uploadViaDestination(config);
} catch (err) {
  if (String(err).startsWith("Missing required destination credential")) {
    logger.error("credential missing; check env/secret injection", { err: String(err) });
    process.exitCode = 1;
  } else throw err;
}

Prevention

When it happens

Trigger: Calling requireCredential(config, key) — via token, apiKey, webhook, authorization, or authToken accessors — when config.credentials[key] is undefined or an empty string.

Common situations: Fresh checkout without the credentials file filled in, CI environments where the secret env var was never set, rotating a token and leaving the field empty, or a typo'd credential key name (e.g. `auth_token` vs `authToken`).

Related errors


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