can1357/oh-my-pi · error · DestinationUnavailableError

${reason}

Error message

${reason}

What it means

A helper that raises DestinationUnavailableError with a caller-supplied reason string. It marks a destination as unusable (not a bug in the caller's code) — e.g. the destination id belongs to an incompatible family or its config fails family-specific validation. The thrown message is whatever `reason` the caller passed.

Source

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

				if (status !== "ok" || !raw) {
					throw new LegacyDestinationError(destination, "the upload node did not return a direct image URL");
				}
				const deleteUrl = xmlElement(text, "delete_url");
				return publication(
					destination,
					request,
					httpUrl(destination, raw),
					deleteUrl ? { delete: { method: "GET", url: httpUrl(destination, deleteUrl) } } : undefined,
				);
			} catch (error) {
				throw failure(destination, error);
			}
		},
	};
}

function incompatible(destination: BlobDestinationId, reason: string): never {
	throw new DestinationUnavailableError(destination, reason);
}

/** Create a viable ShareX legacy HTTP uploader, or `null` for another destination family. */
export function createLegacyUploader(
	destination: BlobDestinationId,
	config: DestinationRuntimeConfig,
): BlobUploader | null {
	try {
		switch (destination) {
			case "s-ul":
				return createSulUploader(config);
			case "sendspace":
				return createSendSpaceUploader(config, sendSpaceEndpoint(config));
			case "streamable":
				return incompatible(destination, "Streamable accepts video and cannot publish a direct image URL");
			case "youtube":
				return incompatible(destination, "YouTube accepts video and cannot publish a direct image URL");
			case "vault":

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the full thrown message — the embedded reason names the exact incompatibility.
  2. Check that the destination id in your config matches a supported family (legacy ShareX HTTP, S3, B2, etc.).
  3. Align the destination config options with the requirements of the intended family.
  4. Pick a different destination id if the service genuinely is not a legacy ShareX HTTP uploader.

Example fix

// before
{ "id": "myhost", "type": "legacy-http" } // but myhost is an S3-compatible service
// after
{ "id": "myhost", "type": "s3", "bucket": "images", "region": "us-east-1" }
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED_FAMILIES = new Set(["legacy-http", "s3", "b2", "backblaze", "owncloud", "nextcloud"]);
if (!SUPPORTED_FAMILIES.has(destination.type)) {
  throw new Error(`destination type '${destination.type}' is not supported; expected one of ${[...SUPPORTED_FAMILIES]}`);
}

Type guard

function isSupportedDestination(d: { type: string }): d is { type: "s3" | "b2" | "legacy-http" } {
  return d.type === "s3" || d.type === "b2" || d.type === "legacy-http";
}

Try / catch

try {
  const uploader = createUploader(destination, config);
} catch (err) {
  if (err instanceof DestinationUnavailableError) {
    console.error(`Cannot use destination: ${err.message}`); // reason is embedded
  } else throw err;
}

Prevention

When it happens

Trigger: createLegacyUploader (or a sibling factory) determines the destination id/config cannot be served by that uploader family and calls incompatible(destination, reason); the reason text is embedded verbatim in the message.

Common situations: Destination configured with an id that maps to a different uploader family; destination config missing family-required options; user pointed the broker at a service the legacy uploader does not recognize.

Related errors


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