Blog image

Critical Betaflight GPS Bug That Can Freeze Your FC Mid-Flight

A Betaflight GPS-related bug that can cause a crash mid-air, and how to fix it

BetaflightSafety
Published on
Updated on
Written by Yaros

Intro

This article covers a pretty obscure but critical Betaflight bug related to how the Flight Controller communicates with the GPS. If configured incorrectly, it can cause the FC to freeze mid-air and remain locked until power-cycled.

Affected setups

At the time of writing, this issue has been observed on Betaflight 4.4 and newer, with GPS enabled on a configured UART where communication fails during initialization.

Tested hardware:

  • FCs: Reliably reproduced on F7 MCUs, potentially affects other MCU types as well
  • GPS: Observed across multiple GPS models
  • Protocol: Observed on UBLOX, potentially affects NMEA as well

Issue uncovered

The issue is triggered when Betaflight expects GPS communication on a UART but cannot initialize the GPS correctly, where a disconnected, missing, or misconfigured GPS can completely freeze the FC in-flight, and it doesn’t recover until unplugging the battery completely.

The issue can occur when ALL of the following are true:

  • GPS is enabled in the Ports tab
  • Betaflight expects a GPS on that UART
  • The GPS is disconnected, powered incorrectly, wired to the wrong UART, or using the wrong baud rate
  • Betaflight cannot initialize communication with the GPS
Peripherals column in Betaflight Configurator

Look at the image above - GPS is enabled on UART2. In itself is not an issue, but if the GPS is not actually connected to UART2, it can trigger the issue.

Warning

It is important to note that this is not related to GPS Rescue or Failsafe modes, rather the Ports tab specifically.

It does not matter if GPS Rescue is configured or not, as long as GPS is active in the Ports tab and Betaflight isn’t communicating with it properly, this issue can happen.

If you have a GPS installed, the issue can still happen if the connection between the FC and GPS is interrupted. When this happens, all GPS-related OSD elements will disappear.

Info

This issue is already reported on the Betaflight’s GitHub Issue Tracker, track here

If you had this issue happen, please report there! Include your full CLI dump and blackbox logs (if possible).

Example of the issue

Unfortunately, I’ve had this happen multiple times before I figured out what was causing this.

It can be easily identified:

  • The drone randomly falls out of the sky
  • Looks similar to a motor stall/desync
  • BUT the OSD freezes (and on DJI, disappears shortly after)
  • Drone doesn’t arm or react to any commands from the TX, although still bound

Here is a video example of the issue happening in-flight:

Notice how the OSD freezes once the drone (and the FC) stalls, then shortly disappears.

Info

Even when the trigger conditions are present, the crash may not occur on every flight.

So if you’re having intermittent issues that look just like the examples above, but they’re not consistent, it still absolutely might be this issue at play!

How to prevent it

Preventing this issue is simple:

  • Always make sure that GPS is enabled in Ports tab ONLY if it is actually attached
  • Make sure it is on the correct UART (Ports tab matches the wiring)

AND if your drone has a GPS, add this simple check to your pre-flight checklist:

  • Verify that the GPS-related OSD elements (like satellite count & distance from home) are present in the OSD prior to take-off

Danger

If GPS-related OSD elements are completely missing before takeoff (when expected), do NOT arm.

If the elements are visible but showing 0 satellites, that is fine.
Missing elements entirely indicates the GPS has not initialized correctly.

This only applies if you normally have GPS OSD elements configured and visible.

Why is it critical?

From testing, the issue appears to fully stall the FC rather than trigger a normal failsafe condition. RX link may remain active, but the FC stops responding entirely until rebooted.

So not only the drone falls out of the sky, but it also cannot be re-armed or even controlled at all until unplugging the battery.

Recovery may become impossible if the quad crashes into water, tall trees, or inaccessible terrain, since turtle mode and the beeper will no longer function.

Should you worry about it?

If your GPS is wired correctly and functioning normally, this issue is unlikely to affect you.

The important part is simply knowing how to identify the warning signs before takeoff:

  • Missing GPS OSD elements
  • Incorrect UART configuration
  • GPS communication failures

A quick pre-flight OSD check is usually enough to avoid the issue entirely.


The technical details

Note

This section is for the curious. You don’t need any of it to stay safe - the prevention steps above are enough on their own.

What Betaflight is actually doing

When you assign a UART to GPS, Betaflight doesn’t know what baud rate your module is set to, so it goes hunting for it.

It sends the GPS a short “who are you?” request, waits about a third of a second, repeats that three times, then switches the UART to the next baud rate in its list and tries again. There are six baud rates in that list, so one full sweep takes roughly six seconds.

The only way out of that loop is the GPS answering.

If a GPS answers, the whole dance is over in about a second and never runs again for the rest of the flight. If nothing answers, it never stops. It keeps stepping through baud rates for as long as the battery is plugged in.

The part that actually matters

Changing the baud rate is not a small operation. To do it, Betaflight shuts the UART hardware down completely and rebuilds it from scratch, every single time.

That rebuild has never been entirely safe to perform while the port is live, and Betaflight’s developers know it - there’s a note left in the firmware, sitting directly above that routine, warning that it doesn’t clean up after itself properly.

For developers: the exact call path

Betaflight calls serialSetBaudRate(), which calls uartReconfigure(). That routine fully tears down the USART peripheral along with both of its DMA streams, then rebuilds them from scratch.

The warning sitting directly above it in the source reads, verbatim:

// XXX uartReconfigure does not handle resource management properly.

The GPS half lives in gps.c, in the GPS_STATE_DETECT_BAUD case. Its only exit is a successfully parsed MON-VER reply from the module, so with nothing on the other end it loops forever.

So the picture looks like this:

GPS status UART torn down and rebuilt
Connected and working about twice, at boot, then never
Configured but not talking about once a second, forever - roughly 3600 times an hour

That is the entire difference. It isn’t the GPS parsing, it isn’t GPS Rescue, and it isn’t the failsafe logic. It is one operation that was never fully safe, repeated a few thousand times per flight instead of twice.

Why that freezes the flight controller

Rebuilding a UART while it’s still live is a gamble. Serial ports constantly interrupt the processor to hand over each new byte as it arrives - and if one of those interrupts lands during the split second when the port is being rebuilt, the flight controller can get stuck answering that same interrupt over and over, forever.

The processor is still running flat out. It just never gets back to the job of flying the quad. Motors stop receiving updates, the OSD freezes on its last frame, and the flight controller stops responding to anything at all. Betaflight has no watchdog to notice this and reset itself, so it stays that way until you unplug the battery.

This isn’t a theory about what could happen. Betaflight has already found and fixed three separate bugs of exactly this shape in the same piece of code. One of those fixes describes this very scenario:

Fixes a UART interrupt-storm freeze that occurs when a UART is configured for GPS but no module is connected: after several hours the flight controller becomes unresponsive (OSD stops updating, control is lost, only a power cycle recovers). Reproduced by reporter on CHAMP_H743, HDZero HALO FC, Matek H743 FC, and SpeedyBee F7 V3.

It names the trigger directly, too - the GPS baud-rate hunt, rebuilding the port over and over again.

Why it’s random

Two things have to line up at the same instant:

  1. The scan has to be running. Guaranteed, permanently, whenever the GPS isn’t talking.
  2. A serial interrupt has to land inside a window a few CPU instructions wide, right in the middle of the rebuild.

The first is constant. The second is a coin flip, weighted by how much serial interrupt activity is happening at that moment. That’s why it’s roughly 1 flight in 10 rather than every flight, and why a flight controller can sit on the bench for hours without a single freeze.

It also explains why it’s worse in the air. An unconnected GPS pin is left floating with no pull resistor, so it picks up electrical noise from the ESCs, and every noise glitch that vaguely resembles a byte is another interrupt. Blackbox logging to flash also stalls the CPU in bursts while serial data keeps arriving. Both load the dice, and both only really happen while you’re flying.

Info

To be honest about the limits here: I know both of those effects are real and both point the same way, but I haven’t measured which one dominates. That part is reasoning, not a measurement.

Why F7 and H7 are hit hardest

The chip manufacturer supplies two different sets of low-level serial code, and Betaflight uses a different one depending on which processor your board has.

F4 boards (F405, F411) get the older, stricter one. Before it reacts to anything the serial port reports, it double-checks that the port was actually asked to report it in the first place. Leftover state gets ignored.

F7, H7 and G4 boards get the newer one, which skips that second check. It will happily act on leftover state that nothing asked for - and that is exactly how the freeze starts.

Two of the three known freeze paths simply don’t exist on F4 as a result. It lines up with the reports, too: almost all of them are F722 and H743 boards.

Warning

F4 is safer here, not immune. It has its own version of the risky teardown window, just with better protection around it.

For developers: which libraries, and the actual difference

F4 uses ST’s Standard Peripheral Library. Its interrupt handler tests with USART_GetITStatus(), which checks the interrupt-enable bit and the flag.

F7, H7 and G4 used ST’s HAL, whose __HAL_UART_GET_IT() reads only the flag, so it can act on state that nothing armed. Betaflight migrated those chips to ST’s LL (Low Layer) API in 2026, which does check both.

F4 also never calls HAL_UART_DeInit() or HAL_DMA_Init(), and that is where the other two freeze paths live. The second of those is a literal while (1); that deadlocks the processor outright if a DMA stream fails to report itself shut down in time.

How far back this goes

I traced it back through Betaflight’s version history. The bug needs two ingredients: the GPS scan that never gives up, and the UART driver that isn’t safe to rebuild. The GPS scan has been there essentially forever. The driver arrived with F7 support.

Version When Affected?
v3.0.x and older up to Oct 2016 No - F7 support didn’t exist yet
v3.1.0 Jan 2017 Yes - the first affected release
v3.2.0 through 4.3.x 2017 - 2022 Yes
4.4.x 2023 - 2024 Yes - first reports appear here
4.5.x 2024 - 2025 Yes - most reports, including mine
2025.12.0 - 2025.12.2 2026 Yes
2025.12.3 and later 2026 Mostly fixed
2026.6 and current dev 2026 Partly fixed

So this has been sitting in Betaflight since January 2017 - about nine and a half years. It only started getting noticed around 4.4 because that’s when GPS became common on ordinary builds, and when F7 and H7 boards took over from F4.

Where the fixes actually are

This is the part I’d most want people to know, because it’s counter-intuitive.

Two driver-level fixes were written. Both of them landed on the 2025.12 maintenance branch. Only one of them was carried forward to the current development version. The result is that 2025.12.3+ is currently better protected against this than the newer releases are.

And more importantly:

Danger

The underlying cause has never been fixed in any version.

Every release - including the newest - still rebuilds the UART about once a second, forever, whenever a GPS is configured but not talking. Only the downstream crash paths have been patched, and only on some branches.

That’s why the advice in this article still stands regardless of which version you run: if there’s no GPS fitted, don’t leave the port assigned to one.

For developers: watching the loop on your own quad

Set debug_mode = GPS_CONNECTION in the CLI, then with a GPS port configured and nothing connected to it:

  • debug[4] sits at 100, which is GPS_STATE_DETECT_BAUD encoded as state x 100 + step
  • debug[2] climbs continuously, counting every baud step and therefore every UART rebuild
  • debug[7] shows bytes waiting in the receive buffer, a rough proxy for how much interrupt activity that floating pin is generating

If debug[4] is parked at 100 and debug[2] keeps climbing while you fly, the trigger is live on your aircraft.


Found this helpful?

If this article saved you some time, consider supporting me - it helps keep the content coming!