Repository navigation
FPP 10.3
FPP 10.3 is a point release on top of 10.2 — 845 commits from 12 contributors in the two and a half weeks since 10.2 shipped. The theme of this release is hardening: we audited fppd, the web UI and the boot tools subsystem by subsystem looking for race conditions, deadlocks, crashes and security holes, and several hundred of these commits fix what that turned up. Alongside it, a brand new regression test suite now runs almost 2,000 tests every night covering most of the changes since FPP 10.0 and the issues we found. The secondary theme is media/light synchronization: lights now follow the audio to within about 15 ms, no longer drift over a song, and MultiSync remotes play in step with the master to within a few milliseconds.
NOTE — PHP security fix: please update and reboot. On October 21 PHP disclosed two critical flaws, known as PHP2Shell (CVE-2026-109618 and CVE-2026-109619), that let anyone who can reach a web server running PHP run code on it without logging in. FPP's web UI runs on PHP, so every player is affected until its PHP is updated. The OS level moves from 2026-10 to 2026-10b for the fixed PHP, and we recommend applying the 10.3 OS update (fppos), which brings the fixed PHP together with the other OS-level security updates. A normal FPP update to 10.3 also installs the fixed PHP from your distribution and asks for a reboot; a player that can't reach the package servers at that moment retries after each boot and daily until it can. Either way, reboot when asked so the web UI runs the fixed PHP.
32-bit Pi image: Raspberry Pi OS's 32-bit package archive has not published the fixed PHP yet, so the 32-bit Pi image and fppos still contain the older PHP. On those players FPP turns off PHP's upload-progress feature (PHP's own workaround for one of the two flaws; FPP never uses it) and installs the fixed PHP automatically, with a Reboot Required prompt, as soon as it is published. The 64-bit Pi, BeagleBone Black and PocketBeagle 2 images already contain the fix.
Behavior changes worth knowing before you update (details under Deprecations & Behavior Changes):
- Other websites can no longer read the FPP API from your browser by default. xLights, fppMon and other non-browser tools are unaffected; a new "Let other websites read the API" setting turns browser access back on if you need it.
- API routes that change something with a GET are deprecated. They still work in 10.x but now say so in a header and the log; FPP 11 will require POST.
- After an FPPOS reflash, native plugins built for the old FPP are not loaded until they are rebuilt or reinstalled.
- File Manager's MP3Gain button now actually changes the volume of the files instead of only analyzing them.
Hardening
The new fpp-tests suite starts a real fppd, built with AddressSanitizer or ThreadSanitizer, drives it over its HTTP API the way the UI, xLights, MQTT and MultiSync do, and fails on a crash, a wedge, a memory error, a data race or a wrong answer. About 1,480 scenarios run nightly under both sanitizers and in a coverage build, another 474 tests drive the web UI in a real browser, and a hardware set runs on a Raspberry Pi 5. Together they cover most of the changes since FPP 10.0 and most of the problems fixed in this release, so those bugs stay fixed. Results, coverage and the parts of FPP no test reaches yet are on the test dashboard — if you'd like to help, that page shows where a new test would do the most good.
Bad configuration no longer takes fppd down
- A wrong-typed value in a hand-edited, restored, plugin-written or API-written config no longer crashes fppd or leaves it crash-looping at startup — for example
"enabled": "yes", a number saved as a string,nan, or a list where one value belongs. This covers channel outputs and output processors, playlists and dynamic playlist entries, the schedule, command presets, variables, sensors, GPIO inputs, recurring tasks, bridge inputs, PipeWire audio groups, AES67/Opus/RTSP/video configs, stream slots, overlay models and xLights submodel/model-group files (such as an upload from FPP Connect). The bad entry is skipped and a new "Configuration Entry Skipped" warning names it; the warning clears once the file is fixed. - Out-of-range values are refused instead of crashing or corrupting memory: output processors, pixel strings and network universes running past the last channel; panels whose output, chain, offset, scan or interleave don't fit; too many outputs for BBB48String, BBBSerial, BBBMatrix, DPIPixels, MAX7219, PCF8574, MCP23017 or USB Pixelnet; Falcon smart-receiver port numbers; and virtual display map pixels outside the buffer. A gamma of NaN no longer runs a string or the whole show at full brightness.
- fppinit no longer stops part way through boot setup on a malformed config file or a system without
/etc/wpa_supplicant, which left network interfaces unconfigured. - A malformed
.fseqor.eseq(truncated upload, full disk, crafted sparse ranges) no longer overflows memory; the unreadable part plays as dark frames instead of random memory on the lights, with one log line instead of one per frame. - An oversized image (a small PNG claiming 30000x30000) can no longer exhaust memory; the image limit scales with the board's RAM.
Reloads, restarts and commands from several places at once
- Saving channel outputs while a show runs is safe: fixed crashes and wedges when a reload overlapped a threaded output sending its last frame, a controller ping, overlay models in use (bulk pixel uploads, effects, the WLED API, image playlist entries), a virtual display drawing, a blank from a playlist stop, or a slow send to a dead controller. A reload no longer waits for unrelated HTTP requests (frames stopped for up to about 6 s), and output processors swap in all at once, so a frame is never sent without its brightness or current-limit processor.
- Media commands from several sources at once no longer crash fppd — Play Media, Stop Media, Stop All Media, Start Playlist, Stop Now, Insert Playlist Immediate and Set Slot Volume arriving together from the UI, API, MQTT and playlists. Starting and stopping playlists from two places at once, two sequence opens at once, and commands arriving while an inserted playlist starts are handled correctly.
- Commands that loop back into themselves stop at 32 levels with a log line instead of crashing fppd: presets that trigger themselves (including a MEDIA_STARTED preset that plays media), If Then/Else lists,
%VAR:expansions, and a Restart/Next/Prev Playlist Item entry that lands on itself. A scheduled hard stop whose Playlist Stopped preset starts another playlist no longer loops forever. - A malformed command no longer crashes fppd: wrong-typed MQTT
/set/commandfields, unknown colour names, unparseable arguments, over-long expressions, malformed command presets and bad overlay effect arguments. - fppd starts even when another program holds the E1.31 or DDP input port, exits promptly so systemd can restart it after a crash (instead of the show going dark for two minutes), and no longer crashes or deadlocks at shutdown.
- Many data races found by ThreadSanitizer are fixed across the output thread, playlists, media status, overlays, MQTT, timers, ping, the Virtual Display, the bridge and MultiSync stats.
- The main loop no longer stalls behind a slow webhook, a slow command preset, a slow virtual display preview browser, a YouTube lookup, a PipeWire daemon that stops answering, an image entry with an empty folder, a dynamic playlist fetching its items, or a flood of E1.31/DDP/ArtNet input or discovery pings.
Clock steps
- A wall-clock jump no longer freezes or misfires FPP. A clock step (an NTP correction, or a cape RTC that has never been set booting the clock back to 2000) could stop every output frame for the size of the step, hold back or fire all at once pending timers (Trigger Command Preset In Future, recurring tasks, GPIO debounce/hold), freeze overlay effects and test patterns, stop media mid-show through the stall watchdogs, stop controller pings and the LOR heartbeat, and leave a startup playlist's Pause waiting for decades. All interval timing now uses a monotonic clock, and schedules that ran early on a board booted with its clock ahead run again at their real time.
Untrusted network input
- A device on the LAN can no longer crash fppd with a malformed MultiSync or discovery answer, a crafted page during controller detection, a crafted WLED audio-sync packet, wrong-typed WLED app requests, or a flood of announcements. Discovery state, MultiSync stats, Twinkly probes and the MQTT message cache are now bounded.
- Pi 4 (and others): pixel output no longer freezes until a power cycle when Wi-Fi stops transmitting mid-show — MultiSync multicast/broadcast sends never block (#3072).
- UDP outputs to a controller whose frames exceed its pacing rate no longer spawn threads until fppd crashes, and a saturated controller with many universes no longer runs fppd out of file descriptors.
- With MultiSync broadcast on, FPP commands sent to all hosts no longer run twice on the sender (including on a player with both Ethernet and Wi-Fi up).
Plugins
- A plugin that throws, hangs or is unloaded mid-call can no longer take fppd down: exceptions from plugin API handlers return HTTP 500, a script plugin that hangs at startup is skipped after 10 s, and a plugin unloaded while another thread was in its callback is no longer called after being freed.
Warnings and logs
- Warning banners now come down when the problem is fixed instead of staying until fppd restarts — output and panel config warnings, Cannot Ping for a removed controller, frame skips on a slow network, schedule warnings, audio card not present, media and video pipeline warnings, RTSP and Opus warnings, receiver eFuse and pixel-count warnings, and the Pi low-voltage warning.
- Many log-every-frame and log-every-packet messages are rate-limited, which protects SD cards (one player had written 360 MB of fppd.log). Log lines containing
%no longer print garbage, and JSON parse errors no longer dump request bodies with credentials into the log.
Security
- PHP2Shell (CVE-2026-109618, CVE-2026-109619): the 10.3 images and fppos carry the fixed PHP (32-bit Pi: see the note at the top), and the normal update installs it on existing players, retrying until it can and asking for a reboot. PHP's upload-progress feature, which FPP never uses, is turned off on every player as PHP's workaround for one of the two flaws.
- The API no longer returns stored passwords and keys (OS login, UI password, GitHub token, MQTT and email passwords, WiFi keys), and the file APIs no longer expose the UI password hash.
- Other websites can no longer change a player from your browser: cross-site POST, PUT and DELETE requests are refused, and cross-site reads of the API are off by default.
- Closed a UI password bypass: a request sent through
/proxy/back to the player's own address counted as "local" and skipped the password. The update fixes existing installs. - The UI password is hashed with bcrypt on multi-core boards (Pi 5, Pi 4, PocketBeagle 2); an existing password is re-hashed the next time it is saved.
- The URL command fetches only http/https (it could read local files as root), and video input URLs are only passed to yt-dlp if they are http(s).
- Cape EEPROMs, including uploaded virtual EEPROMs, are treated as untrusted: a crafted or unsigned image can no longer write files outside its folder, run commands, rewrite boot config beyond
dtoverlay=/dtparam=lines, or change the EEPROM-signing host. - Closed command-injection and configuration-injection holes through settings that reach root shell commands (host name, email, time zone, HDMI, WiFi region and more), the I2C sensor address, the ALSA mixer name, PipeWire/audio page names, media pipeline settings and the network config APIs.
- Closed cross-site scripting holes through scanned WiFi names, file, song, sequence and playlist names, warning text, setting values, MultiSync remotes posing as FPP or Falcon controllers, and other untrusted strings shown in the UI (#3051, #3105).
- Uploads refuse server-executable file types; files served through the file API and the 3D virtual display assets folder are sandboxed; script, playlist, sequence and overlay image names can no longer reach outside their folders; and deleting with an empty name no longer deletes a whole media folder.
- The MultiSync remote helpers and
/api/remoteActioncontact only other players, never this player's own local-only services, and no longer follow redirects. Restoring a backup no longer runs scripts' install steps as root, and the setup wizard's restore is accepted only before setup is complete.
Privacy
- Crash and diagnostic report redaction now also catches more credential formats (curl
-u,--passwordflags, cookies, session ids, common API keys) and coordinates, and the cape serial number is left out everywhere when serial-number sharing is off. - An FPPOS reflash no longer copies a plugin's GitHub token into settings and backups.
Media & Light Sync
- Lights now follow the audio to within about 15 ms instead of 20-50 ms, consistently from one show start to the next, with frame timing corrected smoothly so the cadence never visibly jumps (#3083).
- Lights no longer drift behind the music over a song: frames are scheduled on a fixed cadence, so a five-minute song on a Pi 5 that used to end about 58 ms behind now ends on time.
- Media through PipeWire is paced by the sound card's own clock: a fast card no longer plays short dropouts every half-minute or so, and a slow card no longer lets the sound fall behind the lights. No resampling is added.
- Sound no longer falls progressively behind the lights over a long scheduled show (about 250 ms after an hour on a Pi 4) after an audio stall or xrun; the audio is realigned within a quarter second (#3083).
- MultiSync remotes play their own copy of the show audio in step with the master — a remote gently speeds up or slows down its audio (within 0.5%, inaudible) and lands within about 10 ms of the master on Pi 5, Pi 4 and PocketBeagle 2, instead of hunting or settling 0.4-0.6 s behind.
- MultiSync remotes' lights track the master's to within a couple of milliseconds (a remote could sit up to two frames late depending on how it started), and late sync packets no longer make remote lights jitter. Remote Offset now moves a remote's lights by the exact milliseconds set rather than rounding to a whole frame.
- Video sound plays through the same audio output as music files, so a video's picture, sound and lights stay together, and on a remote a video's sound holds with the master instead of drifting about 180 ms behind.
- Resuming a VBR MP3 after Insert Playlist Immediate no longer leaves the audio 0.1-11 s off from the lights for the rest of the entry (#3087).
- Only the show's own media now paces the sequence; Play Media on another slot or a companion stream used to pull the sequence between two clocks.
- Fixed: a playlist's next sequence stuttering its first frames after the previous one's blanking; a sequence occasionally playing its whole length at the bridging rate (a 40 fps sequence at 20 fps); a media offset shorter than one frame playing the song with no lights; a sequence whose media failed to start once playing lights only on later passes; a remote restarting its media over and over with a media offset and MultiSync; a resumed entry's companion slot playing from 0 for about 4 s; FSEQ frame-trigger presets firing 2-3 times or not at all; and HDMI/framebuffer/DPI outputs stalling media processing during each display refresh.
- New Media Files tab on the Troubleshooting page lists each media file's codec, sample rate, bit rate, length and size, and shows which audio files the CPU has to resample because their rate differs from the audio engine's — a cost on the smaller boards.
Enhancements
Audio & Video
- HDMI outputs survive the display being unplugged and plugged back in, and an HDMI output whose display is off at boot (a projector switched on later) comes up anyway, switching to the display's own mode when it appears. A new warning says when no display is detected (#3102).
- Sound cards are found on non-English systems — FPP installed on a stock Debian with a non-English locale listed no audio devices (#3118). FPP OS images were not affected.
- Video inputs restart themselves when a camera reboots or a stream drops, and AES67, Opus and video streams that fail to start (PipeWire not up yet at boot) are retried automatically instead of staying down until Apply.
- Virtual matrix/framebuffer outputs and video playback can share one display card, and a camera group on an HDMI display steps aside while a video plays there and comes back afterwards.
- Dragging the volume slider no longer stalls light output.
- macOS: media plays through the same GStreamer pipelines as on Linux, with HDMI video in an "FPP Video Output" window.
Plugins
- Upgrading a plugin reloads it in the running fppd instead of requiring an FPPD restart, when its code actually changed.
- The Plugins page accepts a plain GitHub repository address as well as a pluginInfo.json URL.
- Package Manager has an "Install All Missing" button (for example after an OS upgrade), the plugin update check names the plugins whose check failed (#3046), and the Unknown Plugins health check names the plugins behind it.
MultiSync & Discovery
- Fleet actions no longer lock up the browser: Upgrade, OS Upgrade, Copy Files and Change Branch run over one connection, finish even if the page is closed, and report a failure with its reason instead of "Done", with Retry for a single failed system.
- Remotes that are mid-update show as "Upgrading" with the stage, and clicking one opens a live view of its update log that follows it across its restart.
- Copy Show Files gains a "Copy Images" option (#3095).
- The MultiSync receive buffer holds about ten times as many packets, so a large show coming up at once no longer drops sync and ping packets, and MultiSync pings carry the sender's UUID so two controllers with the same host name are told apart.
Updates & Upgrades
- Update progress survives a page refresh and shows on any browser, with a spinner in the header, progress on the About page and a banner when it finishes; a second update can't be started while one runs (#3070).
- A power loss right after an update no longer leaves fppd zero-filled and unbootable — builds are synced to disk, and the About page detects a damaged build and offers Rebuild FPP (#3120).
- When a newer release is offered, the About page also offers "Update to latest" on the version you are running.
Capes & Hardware
- PocketBeagle 2: DMX, Renard, LOR and LOR Enhanced outputs work on PocketBeagle capes (such as the K8-PB) whose line driver sits on a pin with no UART transmit on the PB2 — a PRU sends the serial stream on that pin, with no config change needed.
- Pi 5: a new "RPI Power Supply" readout on the Troubleshooting page shows the measured input voltage, estimated power, supply rating, USB current limit, throttle flags and temperature (#3077).
- Current-based pixel counting reliably counts low-current (seed) pixels on noisy current sensors, including PocketBeagle 2 capes, and no longer counts null nodes.
- Compute Module 4/5: a setting chooses the on-board or external WiFi antenna.
- Pi 5 on new 64-bit images: a Developer setting can switch to the 16K-page kernel.
Pixel Strings & Serial Outputs
- LOR Enhanced sends only the pixels that changed, paced to the serial line rate, so many more units fit on one network (16 units of 170 pixels at 1 Mbps and 40 fps stay in sync), and units that miss a packet recover within a second. The setup page defaults to 1 Mbps and calculates the channel count from the units.
- USB serial adapters can be picked by a name that survives reboots (the
/dev/serial/by-idor USB socket name), and xLights can read those names from the API. - LOR outputs stay in sync between sequences and are budgeted to the 19.2k line rate, so fades no longer trail the audio.
- ColorLight 5A-75 output does its per-frame work in half the time on a BBB, with identical output.
Scheduler, Playlists & Commands
- A schedule entry on a lunar holiday past the end of the built-in tables (2035) raises a warning instead of silently moving the show.
- Set Slot Volume on an idle media slot keeps the volume for that slot's next start.
- The playlist editor asks Save / Discard / Cancel before you leave with unsaved changes.
Diagnostics & Web UI
- A new warning appears when a unicast controller needs more bandwidth than its pacing rate allows (stuttering lights), with a link to fix it.
- Troubleshooting commands can be hidden by UI level, with a Dev Tools tab at Developer level (#3062).
- Location Lookup falls back to a second service when the first is rate limiting (common on cellular networks).
Performance
- Audio playback on single-core boards uses much less CPU: an mp3 on a BBB drops from about 30% to 18% of the core.
- The status API that every open page polls drops from about 566 ms to 151 ms on a BBB.
- Faster startup with no network configured, faster
fppdstop, and much less work when reloading E1.31/DDP/ArtNet configs with many destinations.
Developer
- Every state-changing API route now also accepts POST, and FPP's own UI, fppd, fppoled and the
fppCLI use it. /fppdws?quiet=1lets monitoring clients skip status frames where only the clock changed.- Plugins using FPP's HTTP helpers get a failed request when a transfer is cut off or times out, instead of a truncated body reported as 200.
fpp --log-levelworks again.
Bug Fixes (since 10.2)
Crashes, races and security fixes are summarized under Hardening above; this section lists the rest by area.
Pixel Strings & Panels
- WRGB, WRBG, WGRB, WGBR, WBRG and WBGR colour orders showed the wrong colours on BBB48String, BBShiftString and DPIPixels strings.
- Pixel Strings Save is disabled until the saved config has loaded — pressing Save on a slow page (a phone over Wi-Fi) used to write the defaults over the real config and wipe every string (#3124). E1.31/DDP saves on Channel Outputs and Channel Inputs are protected the same way.
- PocketScroller v2 on an original PocketBeagle is detected again (EEPROM, OLED and panel pin map), a 10.2 regression (#3127).
- LED panel test patterns follow the panel color order (a Red Fade lit blue on a BGR panel) (#2891, #3005).
- BBBMatrix with a GPIO clock (Octoscroller-style layouts): pixels no longer bleed into their neighbour, a regression from 9.x.
- BBBMatrix: 6- and 7-bit colour depth no longer wraps brightness; 80x40 1/20 scan panels drive the right rows; "Flip Rows" interleaves are correct on 32x16, 64x64 and 48x48 panels.
- BBB48String: Falcon V4 smart receiver config packets fixed; changes near the end of the frame are no longer skipped; a firmware build failure raises a warning instead of running stale firmware.
- BBB/PocketBeagle PRU outputs: stopping a PRU could leave it running its old program; a failed PRU build no longer loads the previous config's firmware; starting outputs no longer waits on unrelated long-running processes.
- BBShiftPanel: full-height 1/64 scan panels start from a UI-saved config, and the display is no longer held on for a second at stop.
- Falcon V5 receivers: eFuse toggles reach receivers on every listener mux, and stale query packets are no longer resent after an output restart.
- eFuse auto-retry no longer pulses a port back on after outputs were turned off.
- ColorLight 5A-75: a slow or unplugged NIC no longer stalls every other output on the box or shows torn frames.
- DPIPixels: strings no longer show garbage through a reboot (#2895).
- Leaving the Port Status page no longer stops a port test started on Channel Outputs (#3126), and Count Pixels uses each port's current configuration.
- The current monitor page shows every differential receiver block on every cape (#3113).
Network Outputs (E1.31, ArtNet, DDP, KiNet, Twinkly)
- E1.31 sync packets went out the default route instead of the show interface on players with a second network, so controllers never saw sync.
- Multicast and broadcast output no longer goes out the loopback interface when the show interface had no address at startup, and outputs follow a new address when a DHCP lease replaces a fallback address.
- E1.31/ArtNet/DDP outputs to a slow destination no longer send packets that are half one frame and half the next, and bridged input data is no longer torn mid-merge.
- E1.31, ArtNet, DDP and KiNet sequence numbers no longer skip at the start of a sequence.
- Generic UDP outputs no longer go silent after saving the E1.31/DDP config or double their packets on each save.
- ArtNet de-duplication and ArtNet broadcast/sync keep working after a busy moment, and a taken ArtNet port no longer floods the log.
- Twinkly: an output no longer claims several times its real channel range, and a device that comes back online or refuses a login token recovers within seconds.
- A dead controller is reported down even when the player receives a steady trickle of ICMP from it, and a brief ping stall no longer drops controllers that are up.
Serial, DMX & I2C Outputs
- Serial outputs no longer drop the end of a frame when the serial buffer is full (Generic Serial, USB DMX, USB Pixelnet), and a USB DMX break no longer lands in the middle of the previous frame.
- Serial ports configured as 7E1 or 8E1 (for example Renard) no longer silently run as 8N1.
- Generic SPI and SPI WS2801 outputs no longer overwrite their channel data with zeros.
- PCA9685: a single I2C read error can no longer stop a board until a power cycle, and the Servo Position command survives an output reload.
- MQTT output: the %H%, %S%, %I% and %V% tokens publish real values.
Audio & Video
- Pi 4: HEVC video on HDMI no longer shows wrong colours, ghosting or column shearing, and decodes faster.
- Play Media with a loop count of 2 or more no longer freezes at the first end of the file.
- Video sent to pixel overlay models, RTP members and RTSP streams that follow media playback now plays (before, only HDMI worked), gets the first seconds of each video, and ends on time.
- An HDMI audio selection is no longer replaced at boot when the TV is off.
- BeagleBone, PocketBeagle 2 and audio-only shows no longer get fppd restarts or reboots from the pipeline wedge watchdog.
- Sound cards with dB-scaled mixers (such as PCM512x DAC capes) are no longer left at +24 dB on every start and volume change, which overdrove anything fed from the line out, such as an FM transmitter.
- Video failing on one display output no longer stops the media on every other display.
- Two video output groups sharing one HDMI connector no longer crash fppd, and an HDMI/framebuffer model larger than the display is cropped instead of corrupting memory.
- Media files with a
"in the name play, and per-host video variants (song-<host>.mp4) are found again. - A video with no audio track on a headless box plays at its own speed instead of finishing in milliseconds.
- The RTSP audio bridge and Opus RTP streams no longer go silent after a packet or two.
- AES67: receivers and senders rebuild themselves after a pipeline error instead of staying silent while reporting "running", and ptp4l keeps running across an Apply unless the PTP settings changed.
- After an fppos upgrade, an ssh login no longer starts a second per-user PipeWire stack with a duplicate sink.
Scheduler & Playlists
- A graceful stop during an Insert Playlist Immediate no longer leaves the show stuck with every later scheduled show skipped.
- A scheduled playlist paused during its window now stops at the window's end instead of skipping every later scheduled show.
- Remote Falcon: the show no longer goes dark after every viewer request when an inserted playlist's PLAYLIST_STOPPED preset runs Stop Now (#3114).
- Daylight saving fixes: odd/even-day entries ran on the wrong days for the whole DST season, and past-midnight entries ended an hour off on change days.
- A playlist started from the API, MQTT or a command could be wiped as it started, showing "playing" with nothing running.
- A scheduled entry pre-empted by a higher-priority one no longer restarts every time its playlist ends, and pre-emption honours the running playlist's stop type.
- Starting a playlist at an item, or resuming after an fppd restart, keeps the whole playlist loaded and repeats all of it.
- Sun-relative times whose offset carries past midnight are right on every day; Easter-relative holidays are no longer a day late east of UTC; Ramadan and Eid dates for 2031-2035 are corrected.
- Holidays edited in the holiday editor, or a Locale change, take effect without restarting fppd.
- A playlist no longer stalls on an entry that can't start, image entries with a missing folder finish, and a repeating playlist of only commands no longer spins the CPU.
- Branch to item, Start At Item and resume count rows as the editor shows them when a sub-playlist comes earlier, and Insert Random Item no longer always picks the lead-in's first item.
- Playlists whose names are all digits validate (#3131).
Pixel Overlays & Effects
- WLED effects on more than one model no longer share one strip's state, audio-reactive effects no longer react to two slots mixed together, and effects that read pixels back no longer compound Brightness every frame.
- WLED Scrolling Text: January no longer prints "Err", and date and time tokens show the current time.
- Stop Effects on a disabled model takes effect at once, and a Fill or Clear sent right after Stop Effects is no longer blanked.
- Framebuffer models and the Virtual Display: 16bpp devices (SPI TFTs, 16-bit HDMI modes) no longer draw black, and image transitions no longer drop or bleed images.
- SPI TFT (fbtft) displays no longer crash fppd when setting up a Virtual Display or framebuffer model.
- A parent model with enabled submodels is no longer drawn twice per frame, and submodels on an RGBW parent no longer shift colours.
MultiSync
- A remote playing fallback.fseq no longer freezes and stops with the master, and a remote missing the sequence no longer runs its SEQUENCE_STARTED preset several times a second.
- A remote plays sync file names only from its own media folders.
- A box that booted before DHCP answered no longer announces its stale 169.254 address.
- A controller configured as many single-universe outputs is pinged once.
Network & Wi-Fi
- A WiFi client configured for an adapter that isn't plugged in no longer stalls boot for about 90 s; an adapter plugged in later still connects.
<hostname>.localkeeps resolving after boot — avahi's boot-time rename to<hostname>-2is repaired automatically.- Switching from the tethering access point to a WiFi client associates instead of failing until a power cycle (#2825).
- Tethering no longer starts while a cable is still negotiating, and fppd no longer starts on a 169.254 address ahead of the DHCP lease.
- After a network reconnect the clock no longer shows "NTP daemon not synchronized" for up to an hour.
GPIO & Capes
- fpprtc no longer hangs boot forever when an RTC is selected but no chip answers, and on BeagleBones the built-in RTC is now set from the cape's RTC.
- PocketBeagle 2: the UART pin tables use the board's real ttyS names, so opening a port no longer muxes the wrong pin or the console's TX line.
- An empty entry in a cape EEPROM's bootConfig no longer makes cape detection spin forever at boot.
- OLED: no longer stuck on "Booting..." after a cape RTC stepped the clock back; the status page runs at the right speed on capes with buttons and shows "No Network" promptly.
- With libgpiod v2 (Debian 13 images), a relay that was already on is no longer briefly driven low on every GPIO command, and Pi 5 finds the right GPIO chip.
- Driving a pin configured as a GPIO input returns an error instead of silently killing that input.
Backups & Settings
- Backups are ordered and pruned by when they were taken — after moving the time zone west, each new backup was deleted as soon as it was written once 60 existed.
- A settings restore from a backup with no command presets no longer wipes this player's presets.
- Settings values containing
=(such as a base64 password ending in "==") are no longer cut short. - File Copy to and from another player or a USB drive reports a refused mount, no longer leaves a drive mounted, and selects the saved device again (#3107).
- Settings backups include plugins' JSON/XML config files.
- Quickly toggling the rsync, Samba or FTP setting no longer leaves the setting on and the service off (#3107).
- Reset Config removes symlinks instead of deleting the files they point to.
- A backup or File Copy restore no longer looks like an OS reflash, which held back every native plugin.
Web UI
- File Manager no longer shows ghost entries or empty tabs, and keeps a selection after answering No to a delete (#3078).
- The Status page was broken by a stray tag in an inline comment (#3084), and its player controls no longer flash in the corner on load.
- The scheduler date picker shows the selected date in light mode (#3080).
- Pages no longer slow down on a player whose custom update source is unreachable.
- "Copied to clipboard" is shown only when the copy worked, and banners wrap cleanly on phones.
Upgrade & Install
- Upgrading to a release branch created after the player's last fetch no longer fails with "pathspec did not match" (#3055), and the highest release branch is offered rather than the newest commit. These fixes were also delivered on the 10.0, 10.1 and 10.2 branches.
- A manual update with an unreachable update source reports "Upgrade Failed" instead of claiming success.
- An
.fpposfor the wrong architecture reports the failure instead of silently rebooting into the old OS. - Copying to flash or upgrading the OS no longer leaves the old disk as root when
root=is the last token on the boot command line. - Updates no longer append duplicate safe.directory lines to the system git config on every run.
- Installs from a tree without git (a downloaded ZIP) no longer show a 500 on every page.
- FPP_Install.sh no longer aborts when HOME is unset or on minimal bases, and no longer deletes an existing UID 1000 account on a side install.
- One plugin's orphaned config file no longer makes every later package install fail on a dpkg prompt.
Deprecations & Behavior Changes
- Cross-origin API reads are off by default. Web pages on other sites can no longer read the FPP API from your browser; turn on "Let other websites read the API" (Settings → Services) if a browser-based tool needs it. The WLED-compatible
/jsonand/winendpoints keep open access, and xLights and other non-browser clients are unaffected. - State-changing API routes called with GET are deprecated. Every such route now also accepts POST; the GET form answers with a
Deprecation: trueheader and is logged (at most hourly per route and client). FPP 11 will require POST, so update scripts, plugins and integrations now. - Cross-site POST, PUT and DELETE requests are refused. Non-browser integrations are unaffected.
- After an FPPOS reflash, native plugins built for the old FPP are not loaded until they are rebuilt or reinstalled — stale plugins could boot-loop fppd.
- MP3Gain in File Manager now applies the gain to the audio files rather than only analyzing them.
- The WLED "Copy Segment" effect added in 10.2 is removed (it could only fade the model to black); its WLED API number is kept reserved so other effects keep their numbers.
- Restoring a backup no longer runs scripts'
# InstallAction:steps; reinstall a script that needs them. - Plugins that stream HTML or script through StreamURL output must opt in; it renders as plain text by default.
- The URL command fetches only http/https URLs, with a 4 MB response cap.
- An unsigned cape EEPROM's bootConfig may only add or remove
dtoverlay=/dtparam=lines. - Fill and Clear overlay commands now end a model's running effect.
- Start Playlist At Item loads the whole playlist and starts at that row.
- Stop Now / Stop Gracefully from an inserted playlist's PLAYLIST_STOPPED preset are no-ops again, as in FPP 9.
- Run Script reports "Script Not Started" when a script is refused; Trigger Command Preset Slot refuses slot 0 and non-numeric slots.
- Command nesting is limited to 32 levels, inserted playlists to 10 levels, and variable expressions to 4096 characters. Numeric variable names are no longer aliased in expressions (use
%%2%%). - Configs that overran their buffers (see Hardening) are now refused with an error instead of running.
- API answers are stricter: a missing playlist is a 404, a refused setting value or malformed body is a 400,
DELETE /api/fileanswers 404/403, and file sizes are JSON numbers on 64-bit systems. fpp --log-maskis removed (it never worked).
Installation Instructions
The OS level moves from 2026-10 to 2026-10b, and applying it is recommended because it carries the fixed PHP for PHP2Shell (see the note at the top) along with the other OS-level security updates. Every feature and fix in these notes also arrives with a normal FPP update, which installs the fixed PHP from your distribution as well. The other OS-level changes made since 10.2 — masking the per-user PipeWire stack, the missing-WiFi-adapter boot stall, the mDNS host name repair, the PocketBeagle 2 and AM335x pin tables, the original PocketBeagle base overlay, the UI password /proxy fix and the chrony reconnect hook — are applied by the normal update too.
Upgrading from 10.0, 10.1 or 10.2 — recommended: the OS update
Go to the FPP About page (about.php) and click "Manual Update" first — this brings in the upgrade fixes delivered on your current branch. Then go to About → Upgrade OS, pick the 10.3_2026-10b image for your board and start it. FPP downloads the fppos and installs it, FPP 10.3 included. This takes a while; the player reboots into 10.3 when it is done. Afterwards, delete the fppos file from File Manager → Uploads.
Or: the normal update
Click "Manual Update" on the About page, then the green "Upgrade" bar that appears on the main status page. It typically takes 5-10 minutes, and installs the fixed PHP as part of the update. Reboot when it finishes. A player that already took the normal update can still take the OS update later: About shows the 10.3_2026-10b image as an available OS upgrade.
Coming from 10.0 or 10.1, 10.3 includes every 10.1 and 10.2 change, so read the 10.1 and 10.2 release notes too.
Upgrading from 9.x or older
Due to incompatibilities with the underlying libraries, an OS Level upgrade is required, and moving from 32-bit to 64-bit requires re-imaging.
Staying on 9.5 for now? A "Manual Update" on 9.5 installs the PHP2Shell fix on BeagleBone Black and PocketBeagle 2 players, and turns off PHP's upload-progress feature on all of them. 32-bit Pi's on 9.5 can't get a fixed PHP at all: Raspberry Pi OS for Debian 12 has never published PHP security updates. Moving those players to 10.3 is the only fix.
- Fresh install — back up your config, flash the 10.3 image for your board, restore your config.
- In-place upgrade (same architecture only) — make sure you are fully updated on 9.x first, then About → Upgrade OS → pick the
10.3_2026-10bimage for your board. FPP downloads the fppos and installs it. This takes a LONG time. When it reboots into 10.3, delete the fppos file from File Manager → Uploads.
NOTE: In SOME cases the reboot will fail due to library replacement. A power cycle may be needed to get it back up and running.
Which image do I need?
| Board | Image |
|---|---|
| 64-bit capable Pi (3/4/5, Zero 2 W, CM4/CM5) | FPP-v10.3-Pi64.img.zip |
| Older/32-bit-only Pi | FPP-v10.3-Pi.img.zip |
| BeagleBone Black/Green/PocketBeagle/Green Gateway | FPP-v10.3-BBB.img.zip |
| PocketBeagle 2 / PocketBeagle 2 Industrial | FPP-v10.3-BB64.img.zip |
Thanks
Code contributions in the 10.2 → 10.3 cycle came from:
Daniel Kulp, Daryl C, Jessica Ryan, Stuart Ledingham, Pat Delaney, Bill Hartman, Kyle Grymonprez, Bryan Brandau, Greg Hormann, Paul (MrPaulAR) and frenchmakers.
Thanks also to everyone who reported, reproduced and tested issues on GitHub and the forums since 10.2 shipped — a lot of what is in this release came straight from those reports.
Full changelog: 10.2...10.3