can1357/oh-my-pi · error · DestinationUnavailableError
a user-supplied replacement endpoint is required
Error message
a user-supplied replacement endpoint is required
What it means
configuredEndpoint() throws a DestinationUnavailableError when a legacy destination has no user-supplied 'endpoint' option. Legacy image hosts whose original APIs died can only be used if you point them at a replacement (e.g. a self-hosted clone), so the endpoint is mandatory.
Source
Thrown at packages/coding-agent/src/blob-broker/uploaders-legacy.ts:64
}
interface SendSpaceNode {
readonly url: URL;
readonly maxFileSize: string;
readonly uploadIdentifier: string;
readonly extraInfo: string;
}
function failure(destination: BlobDestinationId, error: unknown): Error {
if (error instanceof DestinationUnavailableError || error instanceof LegacyDestinationError) return error;
const message = error instanceof Error ? error.message : String(error);
return new LegacyDestinationError(destination, message, error);
}
function configuredEndpoint(destination: BlobDestinationId, config: DestinationRuntimeConfig): URL {
const raw = optionString(config, "endpoint")?.trim();
if (!raw) {
throw new DestinationUnavailableError(destination, "a user-supplied replacement endpoint is required");
}
let endpoint: URL;
try {
endpoint = new URL(raw);
} catch (error) {
throw new LegacyDestinationError(destination, "the configured endpoint is not a valid URL", error);
}
if (endpoint.protocol !== "https:" && endpoint.protocol !== "http:") {
throw new LegacyDestinationError(destination, "the configured endpoint must use HTTP or HTTPS");
}
const hostname = endpoint.hostname.toLowerCase();
const blocked = BLOCKED_CUSTOM_HOSTS[destination];
if (blocked) {
for (const domain of blocked) {
if (hostname === domain || hostname.endsWith(`.${domain}`)) {
throw new DestinationUnavailableError(destination, "the defunct public endpoint cannot be used");
}
}View on GitHub (pinned to 9690622007)
Solutions
- Add an endpoint option with the replacement host URL, e.g. { "endpoint": "https://my-legacy-clone.example" }
- Check the option key spelling and that the value is non-empty after trimming
- Pick a non-legacy destination type if you have no replacement endpoint to supply
Example fix
// before
{ "kind": "legacy-host", "options": {} }
// after
{ "kind": "legacy-host", "options": { "endpoint": "https://replacement.example.com" } } Defensive patterns
Strategy: validation
Validate before calling
const ep = config.options?.endpoint?.trim();
if (!ep) throw new Error(`legacy destination '${destination}' requires a user-supplied endpoint option`);
new URL(ep); // throws if malformed Type guard
function hasLegacyEndpoint(config: DestinationRuntimeConfig): config is DestinationRuntimeConfig & { options: { endpoint: string } } {
const ep = config.options?.endpoint;
return typeof ep === "string" && ep.trim().length > 0;
} Try / catch
import { DestinationUnavailableError } from "./errors";
try {
const endpoint = configuredEndpoint(destination, config);
} catch (err) {
if (err instanceof DestinationUnavailableError) {
// prompt user to supply a replacement endpoint
}
throw err;
} Prevention
- Always provide an endpoint option for legacy destination kinds
- Validate required options at config load, before any upload is attempted
- Check for empty-after-trim endpoint values (whitespace-only strings)
- Document that legacy hosts have no defaults and need replacement URLs
When it happens
Trigger: Creating a legacy uploader (uploaders-legacy.ts) from a config that omits or has a blank 'endpoint' option — the trim() leaves an empty string and the guard fires.
Common situations: Configuring a legacy host by name only, assuming built-in defaults exist, or the endpoint option key being misspelled/empty after config parsing.
Related errors
- Missing required destination option: endpoint
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE contains an empty provider
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE contains a provider id wit
- ${name} path does not exist: ${trimmed}
- Anthropic thinking budget requires max_tokens greater than $
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/80655143e62d94b8.
Report an issue: GitHub.