can1357/oh-my-pi · error
imageUrls exposure "named-cloudflared" requires imageUrls.pu
Error message
imageUrls exposure "named-cloudflared" requires imageUrls.publicBaseUrl
What it means
The named-cloudflared exposure runs a Cloudflare Tunnel for a hostname you already own, so omp needs to know the public base URL that hostname serves. This error is thrown when config.publicBaseUrl is missing for kind "named-cloudflared". Unlike quick cloudflared, the URL cannot be discovered from output — it must be configured.
Source
Thrown at packages/coding-agent/src/blob-broker/exposure.ts:462
const { proc, baseUrl } = await spawnUrlTunnel(
[binary, "share", "public", `http://127.0.0.1:${port}`, "--headless", "--backend-mode", "proxy"],
parseZrokUrl,
);
return processExposure("zrok", baseUrl, proc);
}
case "bore": {
const binary = requireBinary("bore");
const server = optionString(config, "server", "bore.pub");
if (!server) throw new Error('imageUrls exposure "bore" requires options.server');
const secret = credentialString(config, "secret");
const argv = [binary, "local", String(port), "--to", server];
if (secret) argv.push("--secret", secret);
const { proc, baseUrl } = await spawnUrlTunnel(argv, line => parseBoreUrl(line, server));
return processExposure("bore", baseUrl, proc);
}
case "named-cloudflared": {
if (!config.publicBaseUrl) {
throw new Error('imageUrls exposure "named-cloudflared" requires imageUrls.publicBaseUrl');
}
const binary = requireBinary("cloudflared");
const token = credentialString(config, "tunnelToken");
let argv: string[];
if (token) {
argv = [binary, "tunnel", "--no-autoupdate", "run", "--token", token];
} else {
const configFile = optionString(config, "configFile");
const tunnelName = optionString(config, "tunnelName");
if (!configFile || !tunnelName) {
throw new Error(
'imageUrls exposure "named-cloudflared" requires credentials.tunnelToken or options.configFile and options.tunnelName',
);
}
argv = [binary, "tunnel", "--no-autoupdate", "--config", configFile, "run", tunnelName];
}
const baseUrl = normalizeBaseUrl(config.publicBaseUrl);
const { proc } = await spawnUrlTunnel(View on GitHub (pinned to 9690622007)
Solutions
- Add imageUrls.publicBaseUrl with the tunnel's public origin, e.g. "https://files.example.com" (no trailing slash).
- Create the Cloudflare named tunnel and route its hostname first if it does not exist yet.
- Fall back to kind "cloudflared" (quick tunnel) if you don't own a hostname.
Example fix
// before
"imageUrls": { "exposure": { "kind": "named-cloudflared" } }
// after
"imageUrls": { "publicBaseUrl": "https://files.example.com", "exposure": { "kind": "named-cloudflared" } } Defensive patterns
Strategy: validation
Validate before calling
if (config.kind === "named-cloudflared") {
const base = config.publicBaseUrl;
if (typeof base !== "string" || !/^https?:\/\/[^/]+$/.test(base)) {
throw new Error("named-cloudflared requires publicBaseUrl like https://files.example.com");
}
} Type guard
function hasPublicBaseUrl(c: { kind: string; publicBaseUrl?: string }): c is typeof c & { publicBaseUrl: string } {
return c.kind !== "named-cloudflared" || (typeof c.publicBaseUrl === "string" && c.publicBaseUrl.length > 0);
} Prevention
- Always set publicBaseUrl alongside named-cloudflared
- Validate the full exposure config block at config-load time
- Remember: quick "cloudflared" needs no URL, "named-cloudflared" and "ssh" do
When it happens
Trigger: Selecting exposure kind "named-cloudflared" in imageUrls config without setting imageUrls.publicBaseUrl.
Common situations: User set up a Cloudflare named tunnel but forgot to mirror its public hostname into imageUrls.publicBaseUrl; migrated from "cloudflared" (which needs no publicBaseUrl) to "named-cloudflared" without adding the field.
Understand the failure class
Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.
Related errors
- imageUrls exposure "named-cloudflared" requires credentials.
- imageUrls exposure "ssh" requires imageUrls.publicBaseUrl
- imageUrls exposure "ssh" requires imageUrls.sshTarget
- 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/9517201d3dca9936.
Report an issue: GitHub.