can1357/oh-my-pi · error

Pushbullet upload fields were missing from the destination r

Error message

Pushbullet upload fields were missing from the destination response

What it means

This error is thrown by the Pushbullet blob uploader after it calls POST /v2/upload-request. Pushbullet's upload-request response must contain `data` — an object of S3 presigned-POST fields (awsaccesskeyid, acl, key, signature, policy, content-type) needed to upload the file bytes. When the response body has no `data` object, the uploader cannot perform the S3 upload and throws instead of producing a partially-broken publication.

Source

Thrown at packages/coding-agent/src/blob-broker/uploaders-cloud-drives.ts:415

	const authHeaders = { Authorization: `Basic ${btoa(`${apiKey}:`)}` };

	return {
		destination: "pushbullet",
		async upload(request: BlobUploadRequest) {
			const filename = fileNameFor(request);
			const requestForm = new FormData();
			requestForm.set("file_name", filename);
			const uploadRequestResponse = await expectOk(
				await fetchImpl(`${PUSHBULLET_API}/upload-request`, {
					method: "POST",
					headers: authHeaders,
					body: requestForm,
				}),
				"pushbullet",
			);
			const uploadRequest = (await uploadRequestResponse.json()) as PushbulletUploadRequest;
			const data = uploadRequest.data;
			if (!data) throw new Error("Pushbullet upload fields were missing from the destination response");
			const fileUrl = requiredText(uploadRequest.file_url, "Pushbullet file URL");
			const fileType = requiredText(uploadRequest.file_type, "Pushbullet file type");
			const uploadUrl = requiredText(uploadRequest.upload_url, "Pushbullet presigned upload URL");
			const uploadFields = {
				awsaccesskeyid: requiredText(data.awsaccesskeyid, "Pushbullet AWS access key id"),
				acl: requiredText(data.acl, "Pushbullet upload ACL"),
				key: requiredText(data.key, "Pushbullet upload key"),
				signature: requiredText(data.signature, "Pushbullet upload signature"),
				policy: requiredText(data.policy, "Pushbullet upload policy"),
				"content-type": requiredText(data["content-type"], "Pushbullet upload content type"),
			};
			await expectOk(
				await fetchImpl(uploadUrl, {
					method: "POST",
					body: multipartFile(request, "file", uploadFields),
				}),
				"pushbullet",
			);

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the API key is valid by calling GET /v2/user and confirm the account can create upload requests
  2. Log the raw upload-request response body to inspect what Pushbullet actually returned
  3. Check for a proxy, API gateway, or mock intercepting api.pushbullet.com and altering the body
  4. Pin/monitor the Pushbullet API for breaking changes and update the uploader's response parsing
  5. Retry the upload — transient gateway issues can produce empty bodies

Example fix

// before (stubbed/mock endpoint returns partial body)
const uploadRequest = await response.json();
// after (caller validates before treating it as valid)
const uploadRequest = await response.json();
if (!uploadRequest?.data?.policy || !uploadRequest?.upload_url) {
  throw new Error(`Pushbullet upload-request response incomplete: ${JSON.stringify(uploadRequest).slice(0, 200)}`);
}
Defensive patterns

Strategy: validation

Validate before calling

function isValidPushbulletUploadRequest(body) {
  return !!body && typeof body === 'object' &&
    typeof body.upload_url === 'string' &&
    typeof body.file_url === 'string' &&
    !!body.data && typeof body.data.policy === 'string' &&
    typeof body.data.signature === 'string';
}
const uploadRequest = await res.json();
if (!isValidPushbulletUploadRequest(uploadRequest)) {
  throw new Error('Pushbullet upload-request response incomplete');
}

Type guard

function isPushbulletUploadRequest(v) {
  return typeof v === 'object' && v !== null && 'data' in v &&
    typeof v.upload_url === 'string';
}

Try / catch

try {
  const uploadRequest = await uploadRequestResponse.json();
  if (!isPushbulletUploadRequest(uploadRequest)) {
    throw new Error(`Pushbullet upload-request incomplete: ${JSON.stringify(uploadRequest).slice(0, 200)}`);
  }
} catch (err) {
  logger.error('Pushbullet upload-request failed', { cause: err });
  throw err;
}

Prevention

When it happens

Trigger: POST to https://api.pushbullet.com/v2/upload-request returned 2xx but the parsed JSON body lacked a truthy `data` field — e.g. Pushbullet changed the response schema, a proxy/API gateway stripped or reshaped the body, or the endpoint returned a JSON body that is not the expected {file_url, upload_url, data:{...}} shape.

Common situations: Pushbullet API schema changes; corporate proxies or mock/stub servers returning a simplified 200 body; wrong or revoked API key that yields an unexpected 2xx body; tests hitting a mocked Pushbullet endpoint that only stubs part of the response.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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