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
- Set the credential in the destination config: `{ "credentials": { "apiKey": "..." } }`.
- In CI, ensure the secret is injected (env var or secret manager) and mapped to the right credential key.
- Check the key name spelling against the destination's documented credential key.
- 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
- Wire secrets from env/secret manager at startup and fail fast if any required key is unset.
- Add destination credential keys to a documented checklist for new environments.
- Never log credential values; only the key name is safe to surface.
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
- Failed to load tree-sitter language: {err}
- ${source} response has a missing or invalid Expiration.
- Unable to resolve AWS credentials. Configure static environm
- profile
- sso-token-missing
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/5724a855db2b3ccf.
Report an issue: GitHub.