can1357/oh-my-pi · error · DestinationUnavailableError
the configured command binary does not exist
Error message
the configured command binary does not exist
What it means
A DestinationUnavailableError thrown during ftp/ftps upload when spawning the configured commandBinary fails with ENOENT — i.e. the path/name in options.commandBinary does not exist or is not executable on this machine. It is raised inside upload() because Bun.spawn rejects at call time, wrapped from the generic Error into a destination-unavailable signal.
Source
Thrown at packages/coding-agent/src/blob-broker/uploaders-self-hosted.ts:261
if (protocol === "ftps" && port !== 990) args.push("--ssl-reqd");
args.push(ftpUploadUrl(protocol, host, port, destinationPath));
try {
const process = Bun.spawn(args, {
stdin: request.bytes,
stdout: "ignore",
stderr: "pipe",
cwd: getSafeProjectCwd(),
});
const stderr = await new Response(process.stderr as ReadableStream<Uint8Array>).text();
const exitCode = await process.exited;
if (exitCode !== 0) {
throw new Error(
`${protocol.toUpperCase()} upload command exited with code ${exitCode}: ${stderr.trim().slice(-300)}`,
);
}
} catch (error) {
if (errorCode(error) === "ENOENT") {
throw new DestinationUnavailableError("ftp", "the configured command binary does not exist");
}
throw error;
}
return publication("ftp", request, publicUrl(publicBase, directory, filename));
},
};
}
function createSharedFolderUploader(config: DestinationRuntimeConfig): BlobUploader {
const root = path.resolve(requiredStringOption(config, "root"));
const directory = optionString(config, "path");
const publicBase = requiredStringOption(config, "publicBaseUrl");
httpBase(publicBase, "publicBaseUrl");
return {
destination: "shared-folder",
async upload(request) {
const filename = safeFileName(request);
const target = path.resolve(root, ...pathParts(directory), filename);View on GitHub (pinned to 9690622007)
Solutions
- Locate the real curl path (which curl / command -v curl) and put that absolute path in options.commandBinary.
- Install curl in the runtime environment where uploads execute.
- If the binary exists, fix permissions (chmod +x) and confirm the broker process's PATH includes its directory.
- Verify with a manual spawn from the same environment: /path/to/curl --version should succeed.
Example fix
// before
{ "options": { "protocol": "ftp", "commandBinary": "/usr/local/bin/curl", ... } } // ENOENT in container
// after
{ "options": { "protocol": "ftp", "commandBinary": "/usr/bin/curl", ... } } Defensive patterns
Strategy: validation
Validate before calling
import { $which } from '@oh-my-pi/pi-utils';
const bin = dest.options?.commandBinary;
if (bin && !(await $which(bin))) throw new Error(`commandBinary not found or not executable: ${bin}`); Try / catch
try {
await uploader.upload(request);
} catch (err) {
if (err?.name === 'DestinationUnavailableError' && /command binary does not exist/.test(err.message)) {
// fail fast with operator guidance: fix commandBinary path or install curl
} else throw err;
} Prevention
- Resolve commandBinary to an absolute path at config load (which curl) and store that.
- Smoke-test the binary (curl --version) in the same environment/process PATH as the broker.
- Bake curl into deployment images used for blob uploads.
- Remember fallback PATH differs between interactive shells and daemons/containers — always use absolute paths there.
When it happens
Trigger: options.commandBinary points to a nonexistent file (e.g. /usr/local/bin/curl on a system that has /usr/bin/curl), a bare name not on the PATH of the agent process, or the binary exists but lacks the execute bit.
Common situations: Config authored on macOS (/usr/local/bin/curl via Homebrew) running in a Linux container; CI images without curl; PATH differences between the developer shell and the daemon running the broker; Docker minimal images.
Related errors
- ${protocol.toUpperCase()} requires options.commandBinary poi
- ${protocol.toUpperCase()} upload command exited with code ${
- cannot stat {file}: {error}
- failed to open {} for reading: {}
- imageUrls exposure "${name}" requires the ${name} binary on
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/37f5a8a478ca842a.
Report an issue: GitHub.