Skip to content

I can't send a file more than 16kb with TinyGsm #110

Open

Description

@klepko36

I send a photo to telegram via SIM800 and TinyGSM. If the photo is more than 16384b I get an error "bad request: image_process_failed".

Are there any restrictions on the size of the transferred files and how to correctly transfer large files more than 16 KB using the SSLCLIENT library

I am using ESP32-CAM Gsm module sim800l Arduino IDE V2.0.

#define TINY_GSM_MODEM_SIM800
#define CAMERA_MODEL_AI_THINKER

#include <WiFi.h>
#include <TinyGsmClient.h>
#include <TinyGsmClientSIM800.h>
#include <ArduinoHttpClient.h>
#include <SSLClientESP32.h>
#include <camera.h>
#include <FastBot2.h>
#include <ArduinoJson.h>
#include <Arduino.h>

#define BOTtoken "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"  // your Bot Token (Get from Botfather)

TinyGsm modem(Serial2);

TinyGsmClient client(modem);

SSLClientESP32 telegramSSL(&client);

FastBot2Client bot(telegramSSL);

const char apn[] = "";  //apn
const char user[] = "";              //username
const char pass[] = "";              //pass

void setup()
{

telegramSSL.setCACert(cert);

 Serial.begin(115200);

bool res = cam_init(FRAMESIZE_QQVGA, PIXFORMAT_JPEG);
    Serial.println(res ? "Camera OK" : "Camera ERROR");

 Serial2.begin(115200, SERIAL_8N1, RXD2, TXD2);

Serial.print(F("Waiting for network..."));
  if (!modem.waitForNetwork()) {
    Serial.println(" fail");
    return;
  }

  Serial.println(" OK");

  Serial.print(F("Connecting to "));
  Serial.print(apn);
  if (!modem.gprsConnect(apn, user, pass)) {
    Serial.println(" fail");
    return;
  } else {
    Serial.println(" OK");
  }

  IPAddress local = modem.localIP();
  modem.waitResponse();
  Serial.println(local);

bot.setToken(F(BOTtoken));
bot.setPollMode(fb::Poll::Long, 20000);

}
void loop() //put function inside loop if required
{
String chat_id = "123456789";
String text = "hello!";

Serial.println("Send message");

bot.sendMessage(fb::Message("Hello!", chat_id));

 delay(1000);

camera_fb_t* fbj = esp_camera_fb_get();
        esp_camera_fb_return(fbj);
        fbj = esp_camera_fb_get();
        if (fbj) {
 fb::File f("frame.jpg", fb::File::Type::photo, fbj->buf, fbj->len);
            f.chatID = chat_id;
            bot.sendFile(f, true); 
        }
        esp_camera_fb_return(fbj);
}

Activity

  1. Repository owner deleted a comment from github-actions on May 23, 2025
  2. RobertByrnes commented on May 23, 2025

    @RobertByrnes
    Collaborator

    You are encountering the "bad request: image_process_failed" error when sending images >16KB to Telegram via SIM800 and TinyGSM. This is a common issue due to several factors—let’s break down the probable causes and solutions.


    1. Telegram Bot API File Size Limits

    • Telegram allows sending images up to 20MB via bots (see Telegram Bot API docs: Sending Files).
    • The 16,384 bytes (16KB) limit is NOT from Telegram, but likely from your GSM module, library, or buffer sizes.

    2. SIM800L Module and TinyGSM/SSLClient Limits

    • SIM800L is a very basic GSM modem, with limited RAM and internal buffer size (often as low as 2-4 KB for TCP/SSL send buffers).
    • TinyGSM and SSLClient libraries further limit the chunk size for sending data. If you try to send a buffer larger than the modem or library can handle, the transfer will fail.

    3. Why <16KB Works, But Larger Fails

    • Sending a buffer > the internal buffer size in one call will often:
      • Cause the modem to drop the connection,
      • Or cause a partial/corrupt upload, which Telegram can’t process.

    4. Solution: Chunked/Buffered Uploads

    You must send the file in small chunks, not all at once!
    Here’s how to do it robustly:

    How to Send Large Files with SSLClient/TinyGSM

    A. Use Streaming/Chunked API

    If your HTTP client supports it, use the beginBody()/write()/endRequest() APIs (or similar) to send the file incrementally.

    B. Manually Chunk the Buffer

    If working with a raw HTTP POST/PUT or multipart upload, send the file in 1-2KB chunks:

    // Pseudocode for chunked upload
    size_t max_chunk = 1024; // 1 KB at a time
    size_t sent = 0;
    while (sent < fbj->len) {
        size_t to_send = min(max_chunk, fbj->len - sent);
        telegramSSL.write(fbj->buf + sent, to_send);
        sent += to_send;
    }

    C. For Libraries Like FastBot2

    • Check if it supports chunked sending.
    • If not, you may need to fork/modify the library to send large files in small pieces using the write() method of your client (telegramSSL).

    D. HTTP Multipart:

    • If you’re using multipart/form-data for file upload (which Telegram requires), make sure your HTTP client builds the multipart body and streams the file part in chunks.

    5. Power Supply Issues

    • Large, sustained uploads over SSL require more current.
    • Ensure your SIM800L has a separate, stable 4V power supply (not from ESP32’s 3.3V pin).

    6. Recommendations for Your Code

    • Don’t pass the entire buffer at once to sendFile() if it’s >2-4KB.
    • If using FastBot2/FastBot2Client, check its implementation for file sending. If it uses a single client.write() call for the full buffer, it will fail for big files.
    • If you can, use a WiFi connection for large files, as SIM800L is not reliable for big SSL uploads.

    Summary Table

    Cause/Limit Value Solution
    Telegram API Limit 20 MB Not the cause; check modem/lib instead
    SIM800L Buffer ~2-4 KB Chunk uploads to 1-2 KB per write
    SSLClient/TinyGSM Varies Use streaming, not single large write

    Actionable Steps

    1. Check if FastBot2 supports chunked sending; if not, consider a different library or modifying its source.
    2. Send the image buffer in 1 KB chunks using telegramSSL.write() in a loop.
    3. Power your SIM800L with at least 2A, dedicated 4V supply.
    4. If possible, use WiFi for large file uploads.

    References

  3. RobertByrnes commented on Nov 1, 2026

    @RobertByrnes
    Collaborator

    A correction to my earlier reply: there is not enough evidence here to conclude that SIM800L has a 16 KB total file-transfer limit, or that passing a complete buffer to sendFile() must fail. The previous sample loop was also incorrect because it ignored write()'s return value and advanced by the requested length, which can silently skip unsent data.

    The exact 16,384-byte boundary is worth investigating as a TLS fragment/partial-write boundary, rather than assuming it is a whole-file limit. mbedTLS can write fewer bytes than requested, particularly above the outgoing fragment size; its caller must retry the remaining bytes with the advanced pointer. This repository's SSLClient::write() currently returns the count from send_ssl_data(), which returns the first positive mbedtls_ssl_write() result. An upload layer that assumes that result always equals the requested size could therefore truncate a larger upload. This is a plausible mechanism, not yet a confirmed diagnosis of your setup.

    The posted sketch uses SSLClientESP32.h and SSLClientESP32, whereas this repository exposes SSLClient.h and SSLClient. Please provide the exact repository/version of the SSL implementation actually used, plus FastBot2, its HTTP transport dependency, TinyGSM, and ESP32 core versions. If you tested both SSL implementations, please distinguish the results. I also found the matching upstream report at GyverLibs/FastBot2#37; these investigations can be cross-referenced without assuming that either library is responsible.

    To narrow this down:

    1. Please reproduce with a fixed, known-good JPEG saved outside the camera capture loop, and use the same bytes over Wi-Fi and GSM. Record its exact size and the complete Telegram error response. A server-side image-processing error alone does not prove a TLS or modem failure.
    2. Log each application-level write request and the byte count it returns (lengths only; do not log the bot token or request URL). Check whether a request over 16,384 bytes returns only 16,384 and whether the uploader sends the remaining bytes. Please capture any SSL/TinyGSM errors too.
    3. If the upload layer needs an incremental-write loop, advance only by the number actually returned. Treat a zero return as no progress and abort or apply a bounded retry policy. Keep multipart boundaries and Content-Length correct; splitting a byte buffer across write() calls does not by itself mean HTTP Transfer-Encoding: chunked. Do not add unframed raw writes alongside bot.sendFile().
    4. Keep the camera buffer valid until the synchronous sendFile(f, true) call completes, check capture success before returning a frame buffer, and report the sendFile() result rather than ignoring it.

    For clarity, Telegram currently documents a 10 MB multipart photo-upload limit, not the 20 MB photo limit stated in my previous reply. It is far above the reported boundary: https://core.telegram.org/bots/api#sendphoto

    mbedTLS partial-write contract: https://mbed-tls.readthedocs.io/projects/api/en/v2.28.10/api/file/ssl_8h/#c.mbedtls_ssl_write

    Please retest this repository's implementation on 1.3.3 if applicable, but the 1.3.3 idle-read fix is not a confirmed fix for this upload issue. Keeping this open with help wanted pending the library/version and write-count results.

  4. self-assigned this
    on Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

help wantedExtra attention is needed

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions