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 LocalBlobBackend constructor resolves the configured destination kind either to a serve adapter (tunnel/direct kinds) or an uploader factory. If the kind is neither in SERVE_KINDS nor has a registered uploader, no adapter exists for it and the constructor throws DestinationUnavailableError. This guards against misconfigured or unknown destination ids reaching the broker.
Source
Thrown at packages/coding-agent/src/blob-broker/broker.ts:104
#exposure: { baseUrl: string; stop(): void } | undefined;
#startPromise: Promise<string | null> | undefined;
#upload: ((hash: string, request: BlobUploadRequest) => Promise<BlobPublication | null>) | undefined;
#fetch: typeof globalThis.fetch;
#dead = false;
/** Create one local serving or configured upload backend. */
constructor(config: BlobBrokerWorkerConfig, fetchFn: typeof globalThis.fetch = globalThis.fetch) {
this.#config = config;
this.#fetch = fetchFn;
const servesBlobs = isServeKind(config.kind);
const uploader = servesBlobs
? null
: createConfiguredUploader(config.kind, {
options: config.options,
credentials: config.credentials,
});
if (!servesBlobs && !uploader) {
throw new DestinationUnavailableError(config.kind, "no built-in uploader or serving adapter is implemented");
}
this.#store = new BlobRegistry({ persist: config.persist });
if (uploader) this.#upload = memoizeUploader(uploader);
}
/** Whether this backend can render blobs on fetch. */
get supportsLazy(): boolean {
return this.#upload === undefined;
}
/**
* Start the local server and exposure once (serve mode); resolves to the
* public base URL or `null` after a failure (sticky for this backend).
*/
ensureStarted(): Promise<string | null> {
if (this.#upload) return Promise.resolve(null);
this.#startPromise ??= this.#start();
return this.#startPromise;View on GitHub (pinned to 9690622007)
Solutions
- Correct the destination kind in the blob/imageUrls settings to a supported value (e.g. cloudflared, ngrok, tailscale, ssh, direct).
- Upgrade omp so the destination kind's adapter exists.
- Run the blob broker doctor command to validate the configured destination before starting sessions.
Example fix
// before
new LocalBlobBackend({ kind: "cloudflare" as BlobDestinationId, options: {}, credentials: {} });
// after
new LocalBlobBackend({ kind: "cloudflared", options: {}, credentials: {} }); Defensive patterns
Strategy: validation
Validate before calling
import { isServeKind, isUploaderKind } from "./blob-broker/broker";
const SERVE = ["cloudflared","ngrok","tailscale","ssh","direct","localhost-run","pinggy","devtunnel","zrok","bore","named-cloudflared"];
if (!isServeKind(config.kind) && !isUploaderKind(config.kind)) {
throw new Error(`destination "${config.kind}" has no adapter; pick one of: ${SERVE.join(", ")}`);
} Type guard
function isKnownDestination(kind: string): kind is BlobDestinationId {
return ["cloudflared","ngrok","tailscale","ssh","direct","localhost-run","pinggy","devtunnel","zrok","bore","named-cloudflared"].includes(kind);
} Try / catch
try {
backend = new LocalBlobBackend(config);
} catch (err) {
if (err instanceof DestinationUnavailableError) {
logger.warn("destination unavailable; disabling image URLs", { kind: config.kind });
backend = null;
} else throw err;
} Prevention
- Validate the imageUrls destination id against the supported list at settings-load time.
- Avoid hand-editing config strings; use the settings UI/enum so typos are impossible.
- Pin the omp version that introduced a new destination before enabling it in config.
When it happens
Trigger: Constructing LocalBlobBackend with a BlobBrokerWorkerConfig whose kind is not one of the serve kinds (cloudflared, ngrok, tailscale, ssh, direct, localhost-run, pinggy, devtunnel, zrok, bore, named-cloudflared) and has no uploader implementation — e.g. a typo'd destination id or a new kind added to config before the adapter shipped.
Common situations: Settings file contains an unsupported imageUrls destination string; version skew where a config written by a newer omp is read by an older binary; typo like "cloudflare" instead of "cloudflared".
Related errors
- OpenAI explicit prompt caching is unsupported for ${model.pr
- npm plugin sources are not yet supported. Use git-based sour
- --list-details, --exec, and --exec-batch are not supported b
- 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/e81e8f850ad4efe0.
Report an issue: GitHub.