discordjs/discord.js · error · TypeError

Unable to resolve body.

Error message

Unable to resolve body.

What it means

resolveBody in the undiciRequest strategy throws this TypeError when it cannot turn the provided request body into something sendable: the body is neither a Buffer/Uint8Array, nor a string, nor a supported stream/FormData-like object after all checks. It is a client-side input problem, thrown before any HTTP traffic leaves the process.

Source

Thrown at packages/rest/src/strategies/undiciRequest.ts:84

	} else if (body instanceof UndiciFormData) {
		return body;
	} else if (body instanceof FormData) {
		return globalToUndiciFormData(body);
	} else if ((body as Iterable<Uint8Array>)[Symbol.iterator]) {
		const chunks = [...(body as Iterable<Uint8Array>)];

		return Buffer.concat(chunks);
	} else if ((body as AsyncIterable<Uint8Array>)[Symbol.asyncIterator]) {
		const chunks: Uint8Array[] = [];

		for await (const chunk of body as AsyncIterable<Uint8Array>) {
			chunks.push(chunk);
		}

		return Buffer.concat(chunks);
	}

	throw new TypeError(`Unable to resolve body.`);
}

function globalToUndiciFormData(fd: globalThis.FormData): UndiciFormData {
	const clone = new UndiciFormData();

	for (const [name, value] of fd.entries()) {
		if (typeof value === 'string') {
			clone.append(name, value);
		} else {
			clone.append(name, value, value.name);
		}
	}

	return clone;
}

View on GitHub (pinned to a81ed8a306)

Solutions

  1. Convert the body to a Buffer/string before sending: fs.readFileSync(path) or await readFile(path) for files, JSON.stringify() for raw bodies.
  2. For file uploads, pass files: [{ attachment: buffer, name: 'file.png' }] with a Buffer or stream, never a path string or bare object.
  3. If passing FormData, use the library's re-exported undici FormData or node's global FormData consistently; don't mix realms.
  4. Check the DiscordjsError/wrapper: this is a TypeError — log typeof/value of what you passed into body/files to spot the wrong type.
  5. Ensure RESTOptions.makeRequest/strategy and undici versions are matched to your @discordjs/rest version (stale lockfile can cause realm mismatches).

Example fix

// before
await rest.post(Routes.channelMessages(id), {
  files: [{ attachment: 'avatar.png', name: 'avatar.png' }], // path string -> TypeError
});
// after
const buffer = await fs.promises.readFile('avatar.png');
await rest.post(Routes.channelMessages(id), {
  files: [{ attachment: buffer, name: 'avatar.png' }],
});
Defensive patterns

Strategy: validation

Validate before calling

function assertSendableBody(body: unknown): asserts body is Buffer | string {
  if (Buffer.isBuffer(body) || typeof body === 'string' || body instanceof Uint8Array) return;
  throw new TypeError(`Body must be Buffer/string/Uint8Array, got ${typeof body}`);
}
// for files:
files.forEach(f => {
  if (!(f.attachment instanceof Buffer || typeof f.attachment === 'string' && fs.existsSync(f.attachment) === false)) {
    throw new TypeError('attachment must be a Buffer or readable stream');
  }
});

Type guard

function isSendableBody(b: unknown): b is Buffer | string | Uint8Array {
  return Buffer.isBuffer(b) || b instanceof Uint8Array || typeof b === 'string';
}

Try / catch

try {
  await rest.post(route, { files });
} catch (e) {
  if (e instanceof TypeError && e.message.includes('Unable to resolve body')) {
    console.error('Bad request body type passed to files/body:', inspectBody(files));
  } else throw e;
}

Prevention

When it happens

Trigger: Passing an unsupported body type to a REST request's files/body options — e.g. `files: [{ attachment: 123 }]` with a number, an object where a Buffer/string/stream was required, a Blob/File from an incompatible realm, or a globalThis.FormData that fails conversion — as when uploading attachments via rest.post(Routes.channelMessages(id), { files: [...] }).

Common situations: Downloading an image then forgetting buffer conversion (passing a plain object); passing null/undefined plus an options shape mismatch after a library version change (undiciRequest strategy replaced node-fetch internals); reading file as a path string instead of a Buffer in a Node strategy; mixing browser File objects into a Node process with different undici globals.

Related errors


AI-assisted analysis of discordjs/discord.js@a81ed8a306 (2026-08-30). Data as JSON: /api/errors/4f27398368494206. Report an issue: GitHub.