How to upload files through Telegram bot API using Node.js

I’m trying to upload a file to a Telegram chat using the bot API in JavaScript but getting an error message that says “Bad Request: there is no document in the request”. Here’s my current code:

const filePath = path.resolve(__dirname, "sample.pdf");
const fileData = fs.readFileSync(filePath);
const buffer = Buffer.from(fileData, "binary");
const form = new FormData();
form.append("chat_id", chatId);
form.append("document", buffer, {
  filename: "sample.pdf",
});
form.append("caption", "Here is your requested file");

const apiCall = await fetch(
  `https://api.telegram.org/bot${TOKEN}/sendDocument`,
  {
    method: "POST",
    headers: {
      accept: "application/json",
    },
    body: form,
  }
);

const result = await apiCall.json();
console.log(result);

I want to be able to send different types of files like PDFs, Word documents, or compressed archives from my Node.js server to users in Telegram. What am I doing wrong with the file attachment?

Your file reading approach is the problem. fs.readFileSync() already returns a Buffer when you don’t specify encoding, so wrapping it with Buffer.from(fileData, "binary") is pointless and probably corrupting your data.

Try this instead:

const filePath = path.resolve(__dirname, "sample.pdf");
const fileStream = fs.createReadStream(filePath);
const form = new FormData();
form.append("chat_id", chatId);
form.append("document", fileStream, "sample.pdf");
form.append("caption", "Here is your requested file");

createReadStream works better for bigger files and dodges encoding headaches. Double-check your file path exists too. I’ve used this with PDFs, ZIPs, you name it - works every time.

The issue lies in how you’re managing the file data. Using fs.readFileSync() without any encoding returns a Buffer object directly. Converting it again with Buffer.from(fileData, "binary") results in a corrupted buffer that Telegram cannot process. I’ve encountered this exact issue before and resolved it like this:

const filePath = path.resolve(__dirname, "sample.pdf");
const fileBuffer = fs.readFileSync(filePath);
const form = new FormData();
form.append("chat_id", chatId);
form.append("document", fileBuffer, {
  filename: "sample.pdf",
  contentType: "application/pdf"
});
form.append("caption", "Here is your requested file");

Additionally, eliminate the accept header from your fetch request. The form-data library handles the content type on its own, and adding extra headers can interfere with the multipart boundary. This method works well for PDFs, Word documents, archives, and more.

sounds like a form-data setup probs. install the form-data package using npm install form-data. don’t set content-type headers yourself - let FormData manage it. i faced the same issue & removing the accept header worked for me.

This topic was automatically closed 4 days after the last reply. New replies are no longer allowed.