can1357/oh-my-pi · error · Error

Unsupported S3 destination: ${destination}

Error message

Unsupported S3 destination: ${destination}

What it means

s3Defaults maps a destination id to S3 endpoint defaults and throws for destination ids it does not recognize in its switch, telling you the configured destination is not a supported S3 flavor. This is a programming/config-level guard: an unknown id reached the S3 uploader factory.

Source

Thrown at packages/coding-agent/src/blob-broker/uploaders-object-storage.ts:194

				region: optionString(config, "region", "garage") ?? "garage",
				pathStyle: optionBoolean(config, "pathStyle", true) ?? true,
				publicBaseUrl: optionString(config, "publicBaseUrl"),
				keyPrefix: configuredPrefix(config),
				cacheControl: optionString(config, "cacheControl"),
			};
		case "backblaze-b2": {
			const region = optionString(config, "region", "us-west-004") ?? "us-west-004";
			return {
				endpoint: endpointOption ?? `https://s3.${region}.backblazeb2.com`,
				region,
				pathStyle: optionBoolean(config, "pathStyle", false) ?? false,
				publicBaseUrl: optionString(config, "publicBaseUrl"),
				keyPrefix: configuredPrefix(config),
				cacheControl: optionString(config, "cacheControl"),
			};
		}
		default:
			throw new Error(`Unsupported S3 destination: ${destination}`);
	}
}

function createS3Uploader(destination: BlobDestinationId, config: DestinationRuntimeConfig): BlobUploader {
	const defaults = s3Defaults(destination, config);
	const settings: S3Settings = { ...defaults, bucket: requiredString(config, "bucket") };
	const sessionToken = credentialString(config, "sessionToken");
	const credentials: AwsCredentials = {
		accessKeyId: requireCredential(config, "accessKeyId"),
		secretAccessKey: requireCredential(config, "secretAccessKey"),
		...(sessionToken ? { sessionToken } : {}),
	};
	const request = fetchFor(config);

	return {
		destination,
		async upload(uploadRequest) {
			const key = objectKey(settings.keyPrefix, fileNameFor(uploadRequest));

View on GitHub (pinned to 9690622007)

Solutions

  1. Check the destination id for typos against the supported S3 destination list in uploaders-object-storage.ts.
  2. Use a supported S3-compatible id, or configure the generic S3 destination with explicit endpoint/region options.
  3. If you need a new provider, add a case to s3Defaults rather than reusing an existing id.
  4. Migrate legacy destination ids from older config versions to their current names.

Example fix

// before
{ "type": "s3", "provider": "digitalocean-spaces" } // not handled
// after
{ "type": "s3", "provider": "aws", "endpoint": "https://nyc3.digitaloceanspaces.com", "bucket": "images" }
Defensive patterns

Strategy: validation

Validate before calling

const S3_DESTINATIONS = new Set(["aws", "cloudflare-r2", "wasabi", "minio", "generic-s3"]);
if (!S3_DESTINATIONS.has(destination)) {
  console.warn(`'${destination}' has no S3 defaults; supply endpoint/region explicitly or pick a supported id`);
}

Type guard

function isSupportedS3Destination(id: string): boolean {
  return ["aws", "cloudflare-r2", "wasabi", "minio", "generic-s3"].includes(id);
}

Try / catch

try {
  const uploader = createS3Uploader(destination, config);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Unsupported S3 destination")) {
    console.error(`Unknown S3 provider '${destination}'; check supported ids`);
  } else throw err;
}

Prevention

When it happens

Trigger: createS3Uploader is invoked with a BlobDestinationId that falls through the switch's default arm — i.e. an id that is not one of the supported S3-compatible services (aws, cloudflare-r2, wasabi, etc.).

Common situations: Typo in the destination type string in config; new S3-compatible provider added to config before support exists in the broker; destination id from an older config version that was renamed.

Related errors


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