can1357/oh-my-pi · error · LegacyDestinationError
the discovery endpoint returned incomplete upload-node metad
Error message
the discovery endpoint returned incomplete upload-node metadata
What it means
This DestinationUnavailableError is thrown when the ShareX-legacy discovery endpoint responds, but the XML <upload> node is missing one or more of the required attributes: url, max_file_size, upload_identifier, or extra_info. The library requires a fully-specified upload node to construct a viable legacy uploader, and refuses to proceed with partial metadata.
Source
Thrown at packages/coding-agent/src/blob-broker/uploaders-legacy.ts:432
const discovery = new URL(endpoint);
discovery.searchParams.set("method", "anonymous.uploadGetInfo");
discovery.searchParams.set("speed_limit", "0");
discovery.searchParams.set("api_version", "1.0");
discovery.searchParams.set("app_version", "1.0");
const apiKey = credentialString(config, "apiKey");
if (apiKey) discovery.searchParams.set("api_key", apiKey);
const response = await fetchFor(config)(discovery, { method: "GET" });
await expectOk(response, destination);
const xml = await response.text();
if (/\bstatus=(?:"fail"|'fail')/i.test(xml)) {
throw new LegacyDestinationError(destination, "the discovery endpoint rejected the upload request");
}
const rawUrl = xmlAttribute(xml, "upload", "url");
const maxFileSize = xmlAttribute(xml, "upload", "max_file_size");
const uploadIdentifier = xmlAttribute(xml, "upload", "upload_identifier");
const extraInfo = xmlAttribute(xml, "upload", "extra_info");
if (!rawUrl || !maxFileSize || !uploadIdentifier || !extraInfo) {
throw new LegacyDestinationError(destination, "the discovery endpoint returned incomplete upload-node metadata");
}
return {
url: new URL(httpUrl(destination, rawUrl)),
maxFileSize,
uploadIdentifier,
extraInfo,
};
}
function createSendSpaceUploader(config: DestinationRuntimeConfig, endpoint: URL): BlobUploader {
const destination = "sendspace" as const;
return {
destination,
async upload(request: BlobUploadRequest) {
try {
const node = await discoverSendSpaceNode(config, endpoint);
const body = multipartFile(request, "userfile", {
MAX_FILE_SIZE: node.maxFileSize,View on GitHub (pinned to 9690622007)
Solutions
- Verify the discovery URL returns ShareX-style XML with all four attributes on the <upload> node (curl the URL and inspect).
- Check the image host's documentation for the correct custom-uploader JSON/XML endpoint path.
- Confirm the destination config's URL is not redirected to an HTML login or error page (check with curl -L).
- If the host genuinely omits a field, switch the destination to a different uploader family (S3/B2/object storage) supported by the broker.
Example fix
// before discoveryUrl: "https://host.example.com/" // returns HTML landing page // after discoveryUrl: "https://host.example.com/sharex-config.xml" // returns XML with <upload url=... max_file_size=... upload_identifier=... extra_info=...>
Defensive patterns
Strategy: validation
Validate before calling
const xml = await Bun.file(discoveryUrl).text();
const required = ["url", "max_file_size", "upload_identifier", "extra_info"];
const upload = xml.match(/<upload\b[^>]*>/)?.[0];
if (!upload || !required.every((attr) => new RegExp(`${attr}="[^"]+"`).test(upload))) {
throw new Error("discovery endpoint missing required <upload> attributes");
} Type guard
function hasUploadAttributes(xml: string): boolean {
const node = /<upload\b[^>]*>/.exec(xml)?.[0];
return !!node && ["url", "max_file_size", "upload_identifier", "extra_info"]
.every((a) => node.includes(`${a}="`));
} Try / catch
try {
await publish(destination, request);
} catch (err) {
if (err instanceof LegacyDestinationError && err.message.includes("incomplete upload-node metadata")) {
// fall back to another destination or surface a config error to the user
} else throw err;
} Prevention
- curl the discovery URL after any host upgrade and diff the <upload> attributes
- pin the image host to a version known to emit full ShareX XML
- monitor for HTML responses (login/error pages) at the discovery URL
- prefer broker destinations with explicit config (S3/B2) over screen-scraped discovery when possible
When it happens
Trigger: The destination's discovery URL returns XML whose <upload> element lacks any of the required attributes (url, max_file_size, upload_identifier, extra_info), typically because the remote custom uploader endpoint changed its schema or returned an error page/HTML instead of the expected ShareX XML config.
Common situations: Self-hosted image host upgraded or replaced its ShareX-compatible endpoint; destination URL points at a login page or HTML error page instead of the XML config; the host omits extra_info or upload_identifier because it uses an older ShareX config dialect.
Related errors
- the upload node did not return a direct image URL
- Destination option ${optionName} must use http or https
- ${reason}
- no built-in uploader or serving adapter is implemented
- replay disabled
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/3c5b1e7327085e86.
Report an issue: GitHub.