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

  1. Verify the discovery URL returns ShareX-style XML with all four attributes on the <upload> node (curl the URL and inspect).
  2. Check the image host's documentation for the correct custom-uploader JSON/XML endpoint path.
  3. Confirm the destination config's URL is not redirected to an HTML login or error page (check with curl -L).
  4. 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

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


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