can1357/oh-my-pi · error

imageUrls exposure "named-cloudflared" requires credentials.

Error message

imageUrls exposure "named-cloudflared" requires credentials.tunnelToken or options.configFile and options.tunnelName

What it means

A named Cloudflare Tunnel must be authenticated two ways: with a tunnel token, or with a config file plus the tunnel name. This error is thrown when neither credentials.tunnelToken nor the pair options.configFile + options.tunnelName is provided. It validates before spawning cloudflared so it fails fast instead of cloudflared exiting with its own cryptic error.

Source

Thrown at packages/coding-agent/src/blob-broker/exposure.ts:473

			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(
				argv,
				() => baseUrl,
				/Registered tunnel connection|Connection [a-z0-9-]+ registered/i,
			);
			return processExposure("named-cloudflared", baseUrl, proc);
		}
		case "ssh": {
			if (!config.publicBaseUrl) throw new Error('imageUrls exposure "ssh" requires imageUrls.publicBaseUrl');
			if (!config.sshTarget) throw new Error('imageUrls exposure "ssh" requires imageUrls.sshTarget');
			const binary = requireBinary("ssh");
			const remotePort = config.sshRemotePort ?? 8787;

View on GitHub (pinned to 9690622007)

Solutions

  1. Set credentials.tunnelToken from `cloudflared tunnel token <tunnel-name>` — the simplest path.
  2. Or provide both options.configFile (path to cloudflared config.yml) and options.tunnelName.
  3. Verify the values are non-empty strings and under the right keys (credentials vs options).
  4. Run `cloudflared tunnel list` to confirm the tunnel exists.

Example fix

// before
"named-cloudflared": { "options": { "configFile": "/etc/cloudflared/config.yml" } }
// after
"named-cloudflared": { "options": { "configFile": "/etc/cloudflared/config.yml", "tunnelName": "omp-files" } }
Defensive patterns

Strategy: validation

Validate before calling

if (config.kind === "named-cloudflared") {
  const hasToken = typeof config.credentials?.tunnelToken === "string" && config.credentials.tunnelToken.length > 0;
  const hasPair = typeof config.options?.configFile === "string" && config.options.configFile.length > 0 &&
    typeof config.options?.tunnelName === "string" && config.options.tunnelName.length > 0;
  if (!hasToken && !hasPair) throw new Error("named-cloudflared: set credentials.tunnelToken or options.configFile+tunnelName");
}

Prevention

When it happens

Trigger: kind "named-cloudflared" with publicBaseUrl set, but no credentials.tunnelToken and either options.configFile or options.tunnelName missing/empty.

Common situations: User created a tunnel in the Cloudflare dashboard but only copied the publicBaseUrl; config file path typo'd so optionString returns undefined; user supplied configFile but forgot tunnelName; token from `cloudflared tunnel token <name>` never pasted into credentials.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/2447142e2bd852df. Report an issue: GitHub.