can1357/oh-my-pi · error · LegacyDestinationError

the upload response omitted URL components

Error message

the upload response omitted URL components

What it means

Thrown when the s-ul.eu upload endpoint returns 200 with no 'error' field, but the JSON is missing one or more of the required URL components: protocol, domain, or filename. The uploader builds the final public URL from these fields, so an incomplete response cannot be published. It indicates an unexpected or partially-failed upstream response.

Source

Thrown at packages/coding-agent/src/blob-broker/uploaders-legacy.ts:212

	} catch (error) {
		throw failure(destination, error);
	}
	return {
		destination,
		async upload(request) {
			try {
				const body = multipartFile(request, "file", { wizard: "true", key: apiKey, client: "sharex-native" });
				const response = await fetchFor(config)(SUL_UPLOAD_URL, { method: "POST", body });
				await expectOk(response, destination);
				const data = await jsonObject(destination, response);
				const upstreamError = firstString(data, ["error"]);
				if (upstreamError) throw new LegacyDestinationError(destination, `upload rejected: ${upstreamError}`);
				const protocol = firstString(data, ["protocol"]);
				const domain = firstString(data, ["domain"]);
				const filename = firstString(data, ["filename"]);
				const extension = firstString(data, ["extension"]) ?? "";
				if (!protocol || !domain || !filename) {
					throw new LegacyDestinationError(destination, "the upload response omitted URL components");
				}
				const url = httpUrl(destination, `${protocol}${domain}/${filename}${extension}`);
				const deleteUrl = new URL(SUL_DELETE_URL);
				deleteUrl.searchParams.set("key", apiKey);
				deleteUrl.searchParams.set("file", filename);
				return publication(destination, request, url, {
					delete: { method: "GET", url: deleteUrl.href },
					remoteId: filename,
				});
			} catch (error) {
				throw failure(destination, error);
			}
		},
	};
}

function createPuushUploader(config: DestinationRuntimeConfig, endpoint: URL): BlobUploader {
	const destination = "puush" as const;

View on GitHub (pinned to 9690622007)

Solutions

  1. Log the raw response body to see what the server actually returned
  2. Retry the upload — transient upstream degradation often produces incomplete payloads
  3. Check s-ul.eu API status/docs for schema changes and update the integration
  4. If persistent, switch the destination to a replacement endpoint configuration

Example fix

// before: assume every response has URL components
const data = await jsonObject(destination, response);
// after: log-and-retry on incomplete payloads
const data = await jsonObject(destination, response);
if (!firstString(data, ["protocol"]) || !firstString(data, ["domain"]) || !firstString(data, ["filename"])) {
	throw new RetryableUploadError(`incomplete response: ${JSON.stringify(data)}`);
}
Defensive patterns

Strategy: validation

Validate before calling

function looksLikeSulUploadResponse(data: unknown): boolean {
	if (typeof data !== "object" || data === null) return false;
	const r = data as Record<string, unknown>;
	return typeof r.protocol === "string" && typeof r.domain === "string" && typeof r.filename === "string";
}
// call after parsing, before relying on the URL

Type guard

function isCompleteSulResponse(d: unknown): d is { protocol: string; domain: string; filename: string; extension?: string } {
	const r = d as Record<string, unknown>;
	return typeof r?.protocol === "string" && r.protocol.length > 0 && typeof r?.domain === "string" && r.domain.length > 0 && typeof r?.filename === "string" && r.filename.length > 0;
}

Try / catch

try {
	return await uploader.upload(request);
} catch (err) {
	if (err instanceof Error && /omitted URL components/.test(err.message)) {
		// retry once or fall back to another destination
		return fallbackUploader.upload(request);
	}
	throw err;
}

Prevention

When it happens

Trigger: POST to SUL_UPLOAD_URL returns valid JSON lacking protocol/domain/filename keys — e.g. a success acknowledgement without URL data, an HTML error page parsed as JSON-ish, or a schema change on the s-ul side.

Common situations: s-ul.eu API schema drift; proxy/interception middleware stripping or rewriting response bodies; the service degrading and returning truncated success payloads.

Related errors


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