can1357/oh-my-pi · error · LegacyDestinationError
credentials ${usernameKey} and ${passwordKey} must be config
Error message
credentials ${usernameKey} and ${passwordKey} must be configured together What it means
This LegacyDestinationError is thrown by optionalBasicHeaders() when exactly one of a destination's paired basic-auth credentials is configured (username without password, or vice versa). Since the two are combined into a single HTTP Basic Authorization header, a half-configured pair can never authenticate, so the library fails fast with a message naming both config keys.
Source
Thrown at packages/coding-agent/src/blob-broker/uploaders-legacy.ts:159
if (!raw) throw new LegacyDestinationError(destination, "the upload response did not include a direct image URL");
return httpUrl(destination, raw, base);
}
function basicAuthorization(username: string, password: string): string {
return `Basic ${Buffer.from(`${username}:${password}`, "utf8").toString("base64")}`;
}
function optionalBasicHeaders(
destination: BlobDestinationId,
config: DestinationRuntimeConfig,
usernameKey: string,
passwordKey: string,
): Headers | undefined {
const username = credentialString(config, usernameKey);
const password = credentialString(config, passwordKey);
if (!username && !password) return undefined;
if (!username || !password) {
throw new LegacyDestinationError(
destination,
`credentials ${usernameKey} and ${passwordKey} must be configured together`,
);
}
return new Headers({ Authorization: basicAuthorization(username, password) });
}
function xmlEntityDecode(value: string): string {
return value
.replaceAll(""", '"')
.replaceAll("'", "'")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll("&", "&");
}
function xmlAttribute(source: string, element: string, attribute: string): string | undefined {
const elementMatch = source.match(new RegExp(`<${element}\\b[^>]*>`, "i"));View on GitHub (pinned to 9690622007)
Solutions
- Set both credential keys in the destination config (the two key names are given verbatim in the error message)
- If the endpoint needs no auth, clear BOTH keys so optionalBasicHeaders() returns undefined instead of throwing
- Check environment/secret injection so both values resolve — one may be empty string or missing
- Re-run with both values present and verify the Authorization header is sent
Example fix
// before
{ basicUsername: "alice" }
// after
{ basicUsername: "alice", basicPassword: "secret" } Defensive patterns
Strategy: validation
Validate before calling
const u = config.basicUsername, p = config.basicPassword;
if ((u && !p) || (!u && p)) {
throw new Error("basicUsername and basicPassword must be configured together");
} Type guard
function hasCompleteBasicAuth(c: { basicUsername?: string; basicPassword?: string }): boolean {
return (!!c.basicUsername && !!c.basicPassword) || (!c.basicUsername && !c.basicPassword);
} Try / catch
try {
await uploader.upload(request);
} catch (err) {
if (err instanceof Error && err.message.includes("must be configured together")) {
// set or clear both credential keys named in the message
} else throw err;
} Prevention
- Always set credential pairs together; never leave one blank
- Validate config at load time: both keys present or both absent
- Check secret-manager/env injection so neither half of the pair is dropped
- When rotating credentials, update both values atomically
When it happens
Trigger: Setting only the username key (e.g. for transfer-sh: only `username`/token without `password`, or lobfile/localhostr pairs) in DestinationRuntimeConfig; the message template embeds the actual key names, e.g. 'credentials basicUsername and basicPassword must be configured together'; thrown while building request headers in createLegacyUploader -> headers.
Common situations: Users fill in a username during setup and skip the password assuming it is optional; secrets managers injecting only one of the two variables; rotating credentials and removing one value; copy-pasting a config example with only one field.
Related errors
- No image API credentials found. Connect a Codex (ChatGPT) su
- No API key available for ${model.provider}/${model.id}. Conf
- Unable to resolve AWS credentials. Configure static environm
- profile
- Invalid QwenCloud Cookie header. Copy the complete Cookie re
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/8a5393542e2a9a31.
Report an issue: GitHub.