can1357/oh-my-pi · error · LegacyDestinationError
the replacement endpoint returned no direct URL
Error message
the replacement endpoint returned no direct URL
What it means
Thrown when the no-credential replacement uploader receives an empty response body after a successful HTTP status. The endpoint is expected to return the direct URL as plain text; an empty body means nothing was uploaded or the endpoint failed silently, so no publication can be created.
Source
Thrown at packages/coding-agent/src/blob-broker/uploaders-legacy.ts:397
throw failure(destination, error);
}
},
};
}
function createTransferUploader(config: DestinationRuntimeConfig, endpoint: URL): BlobUploader {
const destination = "transfer-sh" as const;
return {
destination,
async upload(request) {
try {
const response = await fetchFor(config)(endpoint, {
method: "POST",
body: multipartFile(request),
});
await expectOk(response, destination);
const raw = (await response.text()).trim();
if (!raw) throw new LegacyDestinationError(destination, "the replacement endpoint returned no direct URL");
const deleteUrl = response.headers.get("x-url-delete")?.trim();
return publication(
destination,
request,
httpUrl(destination, raw, endpoint),
deleteUrl ? { delete: { method: "DELETE", url: httpUrl(destination, deleteUrl, endpoint) } } : undefined,
);
} catch (error) {
throw failure(destination, error);
}
},
};
}
async function discoverSendSpaceNode(config: DestinationRuntimeConfig, endpoint: URL): Promise<SendSpaceNode> {
const destination = "sendspace" as const;
const discovery = new URL(endpoint);
discovery.searchParams.set("method", "anonymous.uploadGetInfo");View on GitHub (pinned to 9690622007)
Solutions
- Verify the endpoint URL points at the actual upload API route, not a root/health path
- Test the endpoint manually (curl -F file=@img.png) to see what it returns
- Check whether the service is deprecated/shutting down and choose another replacement endpoint
- Inspect for a proxy layer stripping response bodies
Example fix
// before: endpoint root, returns empty 200 endpoint: "https://transfer-sh.example/" // after: exact upload route that echoes the URL endpoint: "https://transfer-sh.example/upload"
Defensive patterns
Strategy: validation
Validate before calling
// smoke-test the endpoint before relying on it
const probe = await fetch(endpoint, { method: "POST", body: tinyMultipart });
const text = (await probe.text()).trim();
if (!text) throw new Error(`endpoint ${endpoint} returned an empty body`); Try / catch
try {
await uploader.upload(request);
} catch (err) {
if (err instanceof Error && /returned no direct URL/.test(err.message)) {
// endpoint returned 2xx with empty body — switch endpoints or probe manually
}
throw err;
} Prevention
- Point the endpoint at the exact upload API route, not the site root
- Verify the service is alive and still echoes plain-text URLs
- Check for reverse proxies stripping response bodies
- Keep a fallback destination configured
When it happens
Trigger: POST multipart 'file' (no api key) to the configured endpoint; expectOk passes but response.text().trim() is '' — the server returned 2xx with an empty body.
Common situations: Endpoint misconfigured to a health-check or root URL that 200s with no body; service soft-failing with an empty 200; a reverse proxy swallowing the response; the service shutting down but still answering 200.
Related errors
- the replacement endpoint rejected the upload
- the replacement endpoint did not return a direct image URL
- the replacement endpoint omitted the uploaded URL
- upload rejected: ${upstreamError}
- the upload response omitted URL components
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/233d60913ee10267.
Report an issue: GitHub.