{"record":{"id":"aff69be10a410997","repo":"can1357/oh-my-pi","slug":"the-replacement-endpoint-omitted-the-uploaded-url","errorCode":null,"errorMessage":"the replacement endpoint omitted the uploaded URL","messagePattern":"the replacement endpoint omitted the uploaded URL","errorType":"exception","errorClass":"LegacyDestinationError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/uploaders-legacy.ts","lineNumber":352,"sourceCode":"\t\t}\n\t}\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: \"PUT\",\n\t\t\t\t\tbody: multipartFile(request, \"file\", { api_key: apiKey }),\n\t\t\t\t});\n\t\t\t\tawait expectOk(response, destination);\n\t\t\t\tconst data = await jsonObject(destination, response);\n\t\t\t\tconst errors = data.errors;\n\t\t\t\tif (Array.isArray(errors) && errors.length > 0) {\n\t\t\t\t\tthrow new LegacyDestinationError(destination, \"the replacement endpoint rejected the upload\");\n\t\t\t\t}\n\t\t\t\tconst raw = firstString(data, [\"direct_url\", \"directUrl\", \"url\"]);\n\t\t\t\tif (!raw)\n\t\t\t\t\tthrow new LegacyDestinationError(destination, \"the replacement endpoint omitted the uploaded URL\");\n\t\t\t\treturn publication(destination, request, httpUrl(destination, raw, resultBaseUrl));\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 createLobFileUploader(config: DestinationRuntimeConfig, endpoint: URL): BlobUploader {\n\tconst destination = \"lobfile\" as const;\n\tconst apiKey = requireCredential(config, \"apiKey\");\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, \"file\", { api_key: apiKey }),","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/uploaders-legacy.ts#L334-L370","documentation":"Thrown when the replacement endpoint responds without errors but also without any recognizable URL field — none of direct_url, directUrl, or url hold a non-empty string. The uploader needs a direct URL to publish and refuses to return a publication without one.","triggerScenarios":"POST to the replacement endpoint returns valid JSON whose errors array is empty/absent but which lacks all three URL keys — typically a schema mismatch or an HTML/other body that happened to parse as JSON.","commonSituations":"Self-hosted endpoint returning a different response shape than expected; service version drift renaming url fields; a proxy rewriting the response; the service returning a session/HTML page instead of the upload result.","solutions":["Capture the response body and compare its keys with the expected direct_url/directUrl/url fields","Check for a service version change and update the endpoint or adapter configuration","Ensure no middleware/proxy is rewriting the response body","If the endpoint returns relative URLs, verify resultBaseUrl is set so the URL can be resolved"],"exampleFix":"// before: endpoint returns { link: \"...\" } which is not recognized\nendpoint: \"https://host.example/upload\"\n// after: use an endpoint emitting the expected field or set a compatible one\nendpoint: \"https://host.example/api/upload\" // returns { url: \"https://host/i/abc.png\" }","handlingStrategy":"validation","validationCode":"// verify the endpoint returns one of the recognized URL fields before adopting it\nconst probe = await fetch(endpoint, { method: \"POST\", body: tinyFixture });\nconst body = await probe.json();\nif (![\"direct_url\", \"directUrl\", \"url\"].some((k) => typeof body?.[k] === \"string\")) {\n\tthrow new Error(\"endpoint response lacks a recognized direct URL field\");\n}","typeGuard":"function hasRecognizedUrlField(data: unknown): data is { url: string } {\n\tconst r = data as Record<string, unknown>;\n\treturn typeof r?.url === \"string\" && r.url.trim().length > 0;\n}","tryCatchPattern":"try {\n\tawait uploader.upload(request);\n} catch (err) {\n\tif (err instanceof Error && /omitted the uploaded URL/.test(err.message)) {\n\t\t// inspect the endpoint schema; map or transform before using this uploader\n\t}\n\tthrow err;\n}","preventionTips":["Confirm the endpoint's JSON field names before wiring it up","Set resultBaseUrl when the service returns relative URLs","Guard against proxies/HTML interstitials replacing the JSON body","Add an integration probe test for the replacement endpoint"],"tags":["upload","response-parsing","custom-endpoint","legacy-destination"],"backgroundTag":"incomplete-upload-response","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}