can1357/oh-my-pi · error · DestinationUnavailableError
provider-native files must use the provider file channel
Error message
provider-native files must use the provider file channel
What it means
The "provider-files" destination is not an upload destination — provider-native file handling goes through the provider's dedicated file channel. If a caller requests an uploader for it, createConfiguredUploader throws DestinationUnavailableError with this message to redirect the caller to the correct API. It is a routing guard, not a config failure.
Source
Thrown at packages/coding-agent/src/blob-broker/uploaders.ts:158
const command = optionString(config, "command");
if (!command) {
throw new DestinationUnavailableError(destination, "an upload command containing {file} is required");
}
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),View on GitHub (pinned to 9690622007)
Solutions
- Remove "provider-files" from images.urls.destination and use a supported destination (command, a self-hosted/anonymous/legacy/discord destination)
- Use the provider's file API/channel directly instead of the blob broker for provider-native files
- Pick a local-serving or tunnel destination if you only need a URL for shared blobs
- Check BUILTIN_BLOB_DESTINATIONS metadata for destinations that return null (local-serving/tunnel) vs throwing
Example fix
// before
"urls": { "destination": "provider-files" }
// after
"urls": { "destination": "command", "command": "curl -sF 'file=@{file}' https://0x0.st" } Defensive patterns
Strategy: validation
Validate before calling
if (destination === "provider-files") {
// route through the provider file channel instead of the blob broker
return providerFileChannelUpload(request);
} Type guard
function isBrokerUploadDestination(id: string): boolean {
return id !== "provider-files";
} Try / catch
try {
const uploader = createConfiguredUploader(destination, config);
} catch (err) {
if (err instanceof DestinationUnavailableError && err.message.includes("provider file channel")) {
// switch to the provider's native file API instead of the blob broker
}
throw err;
} Prevention
- Treat provider-files as a non-upload id: exclude it from destination pickers
- Use the provider's file API directly for provider-native file storage
- Validate config values against the supported destination list at load time
- When enumerating destinations, handle local-serving/tunnel (null return) separately from throwing ids
When it happens
Trigger: Explicitly setting "images.urls.destination": "provider-files" in config, or programmatically calling createConfiguredUploader("provider-files", config). No fallback uploader exists for this id, so the branch always throws.
Common situations: Misunderstanding the destination list and assuming provider-files is an upload target; migrating config where a previous uploads mechanism was replaced by the provider file channel; tooling that enumerates destinations and tries to instantiate each one.
Related errors
- Missing required destination option: ${key}
- the destination is classified as ${metadata.status}
- an upload command containing {file} is required
- 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/f4f33c6910faedcb.
Report an issue: GitHub.