can1357/oh-my-pi · error · LegacyDestinationError

the replacement endpoint did not return a direct image URL

Error message

the replacement endpoint did not return a direct image URL

What it means

Thrown by the replacement uploader when the endpoint's JSON response contains no usable direct image URL: none of the known URL fields were present, and id/name/publicBaseUrl were insufficient (or absent) to construct one. The library refuses to publish without a resolvable public URL.

Source

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

			try {
				const response = await fetchFor(config)(endpoint, {
					method: "POST",
					headers,
					body: multipartFile(request),
				});
				await expectOk(response, destination);
				const data = await jsonObject(destination, response);
				let raw = firstString(data, ["direct_url", "directUrl", "url"]);
				if (!raw) {
					const id = firstString(data, ["id"]);
					const name = firstString(data, ["name"]);
					const publicBase = optionString(config, "publicBaseUrl");
					if (id && name && publicBase) {
						raw = `${publicBase.replace(/\/$/, "")}/file/${encodeURIComponent(id)}/${encodeURIComponent(name)}`;
					}
				}
				if (!raw)
					throw new LegacyDestinationError(
						destination,
						"the replacement endpoint did not return a direct image URL",
					);
				const remoteId = firstString(data, ["id"]);
				return publication(
					destination,
					request,
					httpUrl(destination, raw, endpoint),
					remoteId ? { remoteId } : undefined,
				);
			} catch (error) {
				throw failure(destination, error);
			}
		},
	};
}

function createLambdaUploader(config: DestinationRuntimeConfig, endpoint: URL): BlobUploader {

View on GitHub (pinned to 9690622007)

Solutions

  1. Inspect the response JSON (available via the wrapped cause/failure) and compare against the expected fields
  2. Set the publicBaseUrl option if the endpoint returns only id/name so the library can build /file/<id>/<name> URLs
  3. Update or replace the endpoint with one that returns a direct_url/url field
  4. Check whether the upstream service changed its API version and adjust configuration

Example fix

// before: endpoint returns only ids, no publicBaseUrl configured
config: { endpoint: "https://host.example/api/upload", apiKey }
// after: supply publicBaseUrl so id+name can form a URL
config: { endpoint: "https://host.example/api/upload", apiKey, publicBaseUrl: "https://host.example" }
Defensive patterns

Strategy: validation

Validate before calling

// ensure publicBaseUrl is set when your endpoint returns ids instead of direct URLs
const cfg = { endpoint, apiKey, publicBaseUrl: "https://host.example" };
new URL(cfg.publicBaseUrl); // throws early if malformed

Type guard

function hasDirectImageUrl(data: unknown): boolean {
	const r = data as Record<string, unknown>;
	return ["direct_url", "directUrl", "url"].some((k) => typeof r?.[k] === "string" && (r[k] as string).trim().length > 0);
}

Try / catch

try {
	await uploader.upload(request);
} catch (err) {
	if (err instanceof Error && /did not return a direct image URL/.test(err.message)) {
		// inspect the endpoint's JSON schema and add publicBaseUrl or switch endpoints
	}
	throw err;
}

Prevention

When it happens

Trigger: Upload to a config-compatible replacement endpoint returns JSON without direct_url/directUrl/url (or id+name with a configured publicBaseUrl), so 'raw' stays falsy after all fallbacks.

Common situations: Replacement service changed its JSON response schema; user configured a self-hosted clone that returns a different field name; publicBaseUrl option missing while the endpoint only returns ids.

Related errors


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