{"record":{"id":"233d60913ee10267","repo":"can1357/oh-my-pi","slug":"the-replacement-endpoint-returned-no-direct-url","errorCode":null,"errorMessage":"the replacement endpoint returned no direct URL","messagePattern":"the replacement endpoint returned no direct URL","errorType":"exception","errorClass":"LegacyDestinationError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/uploaders-legacy.ts","lineNumber":397,"sourceCode":"\t\t\t\tthrow failure(destination, error);\n\t\t\t}\n\t\t},\n\t};\n}\n\nfunction createTransferUploader(config: DestinationRuntimeConfig, endpoint: URL): BlobUploader {\n\tconst destination = \"transfer-sh\" as const;\n\treturn {\n\t\tdestination,\n\t\tasync upload(request) {\n\t\t\ttry {\n\t\t\t\tconst response = await fetchFor(config)(endpoint, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: multipartFile(request),\n\t\t\t\t});\n\t\t\t\tawait expectOk(response, destination);\n\t\t\t\tconst raw = (await response.text()).trim();\n\t\t\t\tif (!raw) throw new LegacyDestinationError(destination, \"the replacement endpoint returned no direct URL\");\n\t\t\t\tconst deleteUrl = response.headers.get(\"x-url-delete\")?.trim();\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, endpoint),\n\t\t\t\t\tdeleteUrl ? { delete: { method: \"DELETE\", url: httpUrl(destination, deleteUrl, endpoint) } } : 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\nasync function discoverSendSpaceNode(config: DestinationRuntimeConfig, endpoint: URL): Promise<SendSpaceNode> {\n\tconst destination = \"sendspace\" as const;\n\tconst discovery = new URL(endpoint);\n\tdiscovery.searchParams.set(\"method\", \"anonymous.uploadGetInfo\");","sourceCodeStart":379,"sourceCodeEnd":415,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/uploaders-legacy.ts#L379-L415","documentation":"Thrown when the no-credential replacement uploader receives an empty response body after a successful HTTP status. The endpoint is expected to return the direct URL as plain text; an empty body means nothing was uploaded or the endpoint failed silently, so no publication can be created.","triggerScenarios":"POST multipart 'file' (no api key) to the configured endpoint; expectOk passes but response.text().trim() is '' — the server returned 2xx with an empty body.","commonSituations":"Endpoint misconfigured to a health-check or root URL that 200s with no body; service soft-failing with an empty 200; a reverse proxy swallowing the response; the service shutting down but still answering 200.","solutions":["Verify the endpoint URL points at the actual upload API route, not a root/health path","Test the endpoint manually (curl -F file=@img.png) to see what it returns","Check whether the service is deprecated/shutting down and choose another replacement endpoint","Inspect for a proxy layer stripping response bodies"],"exampleFix":"// before: endpoint root, returns empty 200\nendpoint: \"https://transfer-sh.example/\"\n// after: exact upload route that echoes the URL\nendpoint: \"https://transfer-sh.example/upload\"","handlingStrategy":"validation","validationCode":"// smoke-test the endpoint before relying on it\nconst probe = await fetch(endpoint, { method: \"POST\", body: tinyMultipart });\nconst text = (await probe.text()).trim();\nif (!text) throw new Error(`endpoint ${endpoint} returned an empty body`);","typeGuard":null,"tryCatchPattern":"try {\n\tawait uploader.upload(request);\n} catch (err) {\n\tif (err instanceof Error && /returned no direct URL/.test(err.message)) {\n\t\t// endpoint returned 2xx with empty body — switch endpoints or probe manually\n\t}\n\tthrow err;\n}","preventionTips":["Point the endpoint at the exact upload API route, not the site root","Verify the service is alive and still echoes plain-text URLs","Check for reverse proxies stripping response bodies","Keep a fallback destination configured"],"tags":["upload","empty-response","custom-endpoint","legacy-destination"],"backgroundTag":"empty-response-body","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}