{"record":{"id":"7146d027db7cec58","repo":"can1357/oh-my-pi","slug":"reason","errorCode":null,"errorMessage":"${reason}","messagePattern":"\\$\\{reason\\}","errorType":"exception","errorClass":"DestinationUnavailableError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/uploaders-legacy.ts","lineNumber":477,"sourceCode":"\t\t\t\tif (status !== \"ok\" || !raw) {\n\t\t\t\t\tthrow new LegacyDestinationError(destination, \"the upload node did not return a direct image URL\");\n\t\t\t\t}\n\t\t\t\tconst deleteUrl = xmlElement(text, \"delete_url\");\n\t\t\t\treturn publication(\n\t\t\t\t\tdestination,\n\t\t\t\t\trequest,\n\t\t\t\t\thttpUrl(destination, raw),\n\t\t\t\t\tdeleteUrl ? { delete: { method: \"GET\", url: httpUrl(destination, deleteUrl) } } : undefined,\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tthrow failure(destination, error);\n\t\t\t}\n\t\t},\n\t};\n}\n\nfunction incompatible(destination: BlobDestinationId, reason: string): never {\n\tthrow new DestinationUnavailableError(destination, reason);\n}\n\n/** Create a viable ShareX legacy HTTP uploader, or `null` for another destination family. */\nexport function createLegacyUploader(\n\tdestination: BlobDestinationId,\n\tconfig: DestinationRuntimeConfig,\n): BlobUploader | null {\n\ttry {\n\t\tswitch (destination) {\n\t\t\tcase \"s-ul\":\n\t\t\t\treturn createSulUploader(config);\n\t\t\tcase \"sendspace\":\n\t\t\t\treturn createSendSpaceUploader(config, sendSpaceEndpoint(config));\n\t\t\tcase \"streamable\":\n\t\t\t\treturn incompatible(destination, \"Streamable accepts video and cannot publish a direct image URL\");\n\t\t\tcase \"youtube\":\n\t\t\t\treturn incompatible(destination, \"YouTube accepts video and cannot publish a direct image URL\");\n\t\t\tcase \"vault\":","sourceCodeStart":459,"sourceCodeEnd":495,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/uploaders-legacy.ts#L459-L495","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the full thrown message — the embedded reason names the exact incompatibility.","Check that the destination id in your config matches a supported family (legacy ShareX HTTP, S3, B2, etc.).","Align the destination config options with the requirements of the intended family.","Pick a different destination id if the service genuinely is not a legacy ShareX HTTP uploader."],"exampleFix":"// before\n{ \"id\": \"myhost\", \"type\": \"legacy-http\" } // but myhost is an S3-compatible service\n// after\n{ \"id\": \"myhost\", \"type\": \"s3\", \"bucket\": \"images\", \"region\": \"us-east-1\" }","handlingStrategy":"validation","validationCode":"const SUPPORTED_FAMILIES = new Set([\"legacy-http\", \"s3\", \"b2\", \"backblaze\", \"owncloud\", \"nextcloud\"]);\nif (!SUPPORTED_FAMILIES.has(destination.type)) {\n  throw new Error(`destination type '${destination.type}' is not supported; expected one of ${[...SUPPORTED_FAMILIES]}`);\n}","typeGuard":"function isSupportedDestination(d: { type: string }): d is { type: \"s3\" | \"b2\" | \"legacy-http\" } {\n  return d.type === \"s3\" || d.type === \"b2\" || d.type === \"legacy-http\";\n}","tryCatchPattern":"try {\n  const uploader = createUploader(destination, config);\n} catch (err) {\n  if (err instanceof DestinationUnavailableError) {\n    console.error(`Cannot use destination: ${err.message}`); // reason is embedded\n  } else throw err;\n}","preventionTips":["validate destination ids/types against the broker's supported list at config load time","keep destination type strings in a shared constant module, not free-form strings","migrate renamed destination ids when upgrading configs","add a startup smoke test that constructs every configured destination"],"tags":["configuration","destination","blob-upload"],"backgroundTag":"unsupported-destination-type","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}