ESP32 HTTPS OTA Update "Magic header does not start with 0xE9"

I am implementing OTA updates using Firebase cloud functions/cloud storage.

What I do is store a firmware.bin, generated by PlatformIO, in cloud storage. I then call a cloud function from my ESP32 that returns the signedUrl with rights to download the firmware.bin.

I receive the error “Magic header does not start with 0xE9”.

I have been copying the code from Arduino-esp32 to try and make this work.

  WiFiClientSecure client;
  client.setTimeout(12000 / 1000);

  Serial.print("Attempting to connect to SSID: ");
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {

  Serial.print("Connected to ");

  if(client.connect(CLOUD_FUNCTION_BASE_URL, 443)) {

    HTTPClient https;
    Serial.print("[HTTPS] begin...\n");
    if (https.begin(client, CLOUD_FUNCTION_URL)) {
      Serial.print("[HTTPS] GET...\n");
      //https.addHeader("Content-Type", "application/json");
      int httpCode = https.GET();

      // httpCode will be negative on error
      if (httpCode > 0) {
        // HTTP header has been send and Server response header has been handled
        Serial.printf("[HTTPS] GET... code: %d\n", httpCode);

        // file found at server
        if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
          SIGNED_URL = https.getString();
      } else {
        Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());

    } else {
      Serial.printf("[HTTPS] Unable to connect\n");

    t_httpUpdate_return ret = httpUpdate.update(client, SIGNED_URL);

    switch (ret) {
        Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());


      case HTTP_UPDATE_OK:
  1. What’s your full platformio.ini for completness?
  2. Are there any other modifications done to the example code besides what you’ve posted? You’ve e.g. adapted the TLS root certificate?
  3. Run the firmware.bin that you store on the server through a hexdump tool (on the commandline if linux/mac or HexDump Online: show contents of a binary file in hex), for like the first 64 bytes. Does the file start with 0xE9?
  4. What is the value of SIGNED_URL before httpUpdate.update()? Can you output it and post it (if it’s not some super secret server, but you still need to verify the correctness)?
  5. Have you verified that when you use your browser to download the file pointed to by SIGNED_URL and run that through a hexdump again, that the first byte is 0xE9?
  6. What’s the serial log output when activating debug logs using build_flags = -DCORE_DEBUG_LEVEL=5 -D DEBUG_ESP_HTTP_UPDATE ?

Wow. So for whatever reason the firmware.bin I had in the cloud did not begin with 0xE9. However I rebuilt a different one and checked and it did. So once I uploaded that, my code worked. Thank you for giving me that web page!

1 Like