can1357/oh-my-pi · error · DestinationUnavailableError
no built-in uploader or serving adapter is implemented
Error message
no built-in uploader or serving adapter is implemented
What it means
The blob broker's createConfiguredUploader() resolves a destination name (e.g. 'r2', 's3') to an uploader implementation. Only certain destinations have built-in adapters; anything else that is not local-serving or tunnel (which return null, meaning handled elsewhere) has no implementation, so the broker throws DestinationUnavailableError. It is a deliberate 'not implemented yet' guard, not a configuration typo check.
Source
Thrown at packages/coding-agent/src/blob-broker/uploaders.ts:161
}
return createCommandUploader(command);
}
const uploader =
createAnonymousUploader(destination, config) ??
createImageHostUploader(destination, config) ??
createCloudDriveUploader(destination, config) ??
createObjectStorageUploader(destination, config) ??
createSelfHostedUploader(destination, config) ??
createLegacyUploader(destination, config) ??
createDiscordUploader(destination, config);
if (uploader) return uploader;
if (destination === "provider-files") {
throw new DestinationUnavailableError(destination, "provider-native files must use the provider file channel");
}
if (metadata.family === "local-serving" || metadata.family === "tunnel") return null;
throw new DestinationUnavailableError(destination, "no built-in uploader or serving adapter is implemented");
}
/** Wrap an uploader with per-hash memoization so bytes upload at most once. */
export function memoizeUploader(
uploader: BlobUploader,
): (hash: string, request: BlobUploadRequest) => Promise<BlobPublication | null> {
const byHash = new Map<string, Promise<BlobPublication | null>>();
return (hash, request) => {
let pending = byHash.get(hash);
if (!pending) {
pending = uploader.upload(request).catch(error => {
byHash.delete(hash);
logger.warn("blob-broker: upload failed; image stays inline", {
uploader: uploader.destination,
error: error instanceof Error ? error.message : String(error),
});
return null;
});View on GitHub (pinned to 9690622007)
Solutions
- Check the destination name in config and switch to a supported destination (provider-files, local-serving, or tunnel)
- Register a custom uploader before calling createConfiguredUploader so the memoized `uploader` short-circuit returns it instead of falling through to the throw
- If you own the code, implement an uploader adapter for the destination family in packages/coding-agent/src/blob-broker/uploaders.ts
- If you only need local serving, use a local-serving family destination, which returns null instead of throwing
Example fix
// before
const up = await createConfiguredUploader({ destination: "gcs", metadata });
// after
const up = await createConfiguredUploader({ destination: "local-serving", metadata }); // or pass a pre-built uploader Defensive patterns
Strategy: validation
Validate before calling
const SUPPORTED = new Set(["provider-files", "local-serving", "tunnel"]);
if (!SUPPORTED.has(destination) && !customUploader) {
throw new Error(`destination "${destination}" has no built-in uploader; provide one or pick a supported destination`);
} Type guard
function hasBuiltInAdapter(destination: string): boolean {
return ["provider-files", "local-serving", "tunnel"].includes(destination);
} Try / catch
try {
uploader = await createConfiguredUploader({ destination, metadata });
} catch (err) {
if (err instanceof DestinationUnavailableError) {
logger.warn("destination unsupported, skipping upload", { destination });
return null;
}
throw err;
} Prevention
- Only configure destinations listed in the broker's supported set
- Register a custom uploader for exotic destinations before resolving
- Handle the null return for local-serving/tunnel families instead of expecting an uploader
- Add a config-check (configChecks) before first real upload
When it happens
Trigger: Calling createConfiguredUploader (via uploader() or configChecks()) with a destination string that has a registered metadata family but no built-in uploader adapter — i.e. any non-'provider-files', non-'local-serving', non-'tunnel' destination whose uploader factory was never implemented.
Common situations: A user configures blob uploads to a custom/exotic destination in settings expecting support; a plugin author adds a destination family without wiring an uploader; a new destination type was added to metadata before the adapter shipped.
Related errors
- the discovery endpoint returned incomplete upload-node metad
- ${reason}
- Destination option ${optionName} must use http or https
- No model configured
- Azure OpenAI base URL is required. Set AZURE_OPENAI_BASE_URL
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/87ed8cb17076a3b9.
Report an issue: GitHub.