upstream contributions

Bugs reported to, and fixed in, other people's projects.


Most of these came out of building something else and hitting a wall: a spatial-audio streaming stack, a studio monitoring setup, a listening-test harness, a home network. The pattern is usually the same – a thing behaves impossibly, the cause turns out to be upstream, and the fix belongs there rather than in a local workaround.

Status is hand-maintained; follow the links for the real, current state.

Spatial audio and rendering

google/eclipsa-audio-plugin

  • Binaural rendering silently outputs digital black below 32-sample host buffers, with no error, log or UI indication – #126, open, unconfirmed by the maintainer
  • Renderer leaves output channels above its bus count unwritten, passing raw pre-render substream audio downstream – #127, open, unconfirmed by the maintainer
  • Bundled Boost 1.86.0 fails to compile under recent Clang: template keyword misuse in boost::qvm, fixed upstream in 1.87.0+ – #128, open, unconfirmed by the maintainer
  • CGWindowListCreateImage obsoleted under the macOS 15 SDK, blocking the build. Traced to the pinned third_party/JUCE fork sitting one commit ahead of upstream JUCE 7.0.12 – a formatting pass and one harmless debug-only assertion, nothing tied to the old JUCE version. The fix already exists upstream: juce-framework/JUCE@10cf5a98a2 gates the legacy call behind a ScreenCaptureKit path for macOS 14.4+ SDKs, first shipped in the stable tag 8.0.2. Verified past the reported failure with a full build (JUCE, protobuf, Spatial Audio Framework) against a substituted current JUCE – the reported error is gone, and the build reaches unrelated territory (an existing Boost/qvm template issue in this plugin’s own code). Offered to send the .gitmodules repoint as a PR – #10, open, unconfirmed by a maintainer

leomccormack/SPARTA

  • Powermap’s webcam selector opens the wrong device, and a failed or cleared switch leaves stale video on screen with no indication – #123, open, unconfirmed by the maintainer

leomccormack/sparta-reaper-examples

  • Powermap visualisations over video or a still image – #1, open, unconfirmed by the maintainer

chris-hld/spaudiopy

  • Version mismatch in package metadata – #19, closed

eshaz/wasm-audio-decoders

  • opus-decoder: the minified browser bundle mangles the constructor’s own option names (channels, streamCount, coupledStreamCount, channelMappingTable, preSkip, forceStereo) and the decode result’s errors field, so a multichannel configuration is silently ignored – the decoder falls back to stereo defaults, returns 2 channels for a 16-channel stream, with no error reported. Confirmed by counting name occurrences in the shipped bundle (absent) against src/ (present); the same packets decoded correctly when bundled from source instead. Easy to miss because stereo is what the ignored options default to anyway, and multichannel Opus is separately broken in several browsers right now, so a quietly-smaller channel count looks like the platform’s fault rather than the library’s – #129, closed, fixed by 11530fe and released same day in opus-decoder@0.7.12

QxLabIreland/Ambiqual

  • calculate_ambiqual raises NameError on every run – an incomplete variable rename left n_channels referenced but never assigned (the split into n_channels_ref/n_channels_deg is complete everywhere else in the file), so the published tool cannot produce a score as shipped. Proposed a fix (min(n_channels_ref, n_channels_deg), matching what the NaN-handling immediately below already assumes) but left the actual choice to the maintainer, since rejecting mismatched-channel inputs outright instead of scoring them is a legitimate alternative. Also flagged a pinned numpy==1.23.5 with no wheel for current Python. Found while producing the scores behind the codec-quality measurements on the 360 livestream project page. Fixed on main within two days, using the same guard proposed here; testing the follow-up numpy relaxation surfaced a second, unrelated defect – vnsim.py passes a float64 phaseogram into cv2.remap, an input type OpenCV 5.0 silently accepts and corrupts while 4.10 handled the same call correctly, moving scores by up to 2.7% (quality) and 5.9% (localisation) on real material. Traced to cubic interpolation reading NaN from neighbouring pixels even where its own sample weight is zero; a float32 cast is the proper fix, one already-published scores never needed since the exact version pin kept them off the broken path. Both fixes landed on main within a day of being reported – #2, open, fixed on main, closing pending

Streaming stack

The HOA 360 livestream work. See ambisonic-box for what these were found with.

EnvelopSound/Earshot – maintainer since August 2026. 27 merged pull requests:

  • Align track starts at the relay so DASH output carries no video edit list, the server-side half of a cross-browser A/V desync – #53, merged
  • Enable libvpx in ffmpeg so VP9 is actually available – #54, merged
  • Clear the DASH directory contents instead of rm -rf on the mount – #55, merged
  • nginx: emit relative redirects so a mapped host port survives directory redirects – #56, merged
  • Allow building without --enable-nonfree for a redistributable image – #57, merged
  • Floor DASH suggestedPresentationDelay to avoid live-join gap-jumps – #58, merged
  • Decouple the DASH manifest filename from the RTMP stream key – #59, merged
  • Raise RTMP max_message so 4K keyframes are not dropped – #60, merged
  • Raise the yarn network timeout so slower hosts can build the webtools image – #61, merged
  • CI: make the workflows run again (actions v4, Compose v2, failure diagnostics) – #62, merged
  • Test: push a real video track in CI, matching the default -c:v copy path, so test goes green again after #62#63, merged
  • Resume the AudioContext from the gain slider’s onChange instead of a leaking window listener; supersedes #26, closes a “no audio playback in Chrome” bug open since 2021 and previously misdiagnosed as an HTTPS/CDN problem – #64, merged
  • Bump 13 webtools dependencies to their already-in-range patched versions – real, named vulnerabilities rather than a routine version chase (ReDoS in moment and word-wrap, a private-key leak via ECDSA nonce reuse in elliptic, prototype pollution in y18n and yaml, code injection via lodash’s _.template), plus five more CVE-fixed packages deliberately left out because their patched versions cascade into dependency-graph conflicts that deserve their own PRs – #70, merged
  • Force LF line endings for shell scripts, regardless of the checkout platform’s git config – entrypoint.sh silently got CRLF-corrupted on Windows checkouts with core.autocrlf=true (no eol rule for .sh files in .gitattributes), baked into the Docker image via COPY, and failed to exec (no such file or directory). Fixes #28#71, merged
  • webtools: patch 29 more vulnerable packages Dependabot can’t auto-fix – 60 of 114 open alerts (8 of 9 critical, 33 of 53 high), continuing #70 into packages pinned by their requesters’ own ranges, where the fix needs a parent bump, a lockfile edit, or a yarn resolutions override. Keystone move is express 4.18.2 to 4.22.2, whose own updated pins carry five more packages with it; path-to-regexp’s ReDoS advisory was the one reachable client-side, confirmed present in the production bundle’s sourcemap via react-router. Deliberately left out: 23 packages needing a breaking major-version override into build tooling, 3 with no patched version at all (abandoned upstream), and postcss’s 8.x-only fixes, stuck on the CRA3-compatible 7.x line – #72, merged
  • webtools: patch a ReDoS advisory in @babel/runtime’s generated code (named capturing groups) via a yarn resolutions override, since babel-preset-react-app exact-pins the version rather than a range. A follow-up to #72’s excluded “needs-care” bucket, worth fixing on its own since the runtime ships its helper functions into whatever the transpiler emits, not just build tooling – #73, merged
  • webtools: patch 5 more same-major-version packages from #72’s excluded “needs-care” bucket, distinguishing genuinely low-risk same-major deltas from the cross-major jumps that stay excluded. Three semver exact-pin blockers scoped individually (react-scripts, core-js-compat, and eight caret-range requesters stuck on a stale resolution); @babel/core bumped via the same exact-pin pattern as #73’s @babel/runtime fix; browserslist targeted the latest 4.x rather than the CVE’s bare-minimum patch, since the minimum left @babel/core unable to find browserslist.findConfigFile – a real build failure the production build caught, not just the install step – #74, merged
  • webtools: close three more old-line stragglers a GitHub weekly digest email caught – packages already fixed on their main line, but with a second, older stanza still sitting inside the vulnerable range that earlier passes missed. braces 2.3.2 (chokidar/micromatch’s jest-only line, wrongly assumed a separate unaffected major in #74) forced to the already-proven 3.0.3; qs “~6.5.2” (the abandoned request package’s own line) forced to the 6.15.3 already fixed elsewhere in #72; minimist 0.0.8 (exact-pinned by mkdirp’s CLI wrapper, unreachable from this project’s actual build path) forced to 1.2.8 – #75, merged
  • webtools: trace nine more “risky” alerts against react-scripts’ actual build.js/start.js require lists instead of assuming core tooling means hands-off. Eight land: webpack-dev-middleware and http-proxy-middleware (only reachable through webpack-dev-server, which this Docker image’s yarn build never runs), node-forge (same dev-server chain, via HTTPS dev certs), micromatch and node-notifier (jest-only, and CI here never runs jest), flatted (only loaded by eslint’s interactive --init wizard, never invoked), tough-cookie (via dashjs’s own request-promise, confirmed absent from the shipped bundle by grep), and tmp, unblocked by bumping the long-EOL node:12/alpine:3.12 build stage to node:24/alpine:3.24 (build-only, changes nothing about what ships). The ninth, webpack-dev-server itself, stays unfixed: it’s react-scripts’ own direct dependency, and react-scripts hard-fails on any version mismatch there regardless of whether the build logic uses it, confirmed by trying it – #76, merged
  • webtools: second pass over uuid and yargs-parser once fixing #76 exposed more of their requesters. uuid’s four chains all trace to jest-only or webpack-dev-server-only paths already proven dead in #76, plus dashjs’s own request-promise dependency; grepping the real build output finds no uuid-formatted strings at all, only dash.js’s own hardcoded DRM key-system identifiers. yargs-parser’s vulnerable stanza is only required by webpack-dev-server too, consolidated to the version already used elsewhere via jest’s own yargs – #77, merged
  • webtools: third round of the same lesson – is-svg, nth-check, and svgo were previously assumed “genuinely build-reachable” in #76 because their loader, @svgr/webpack, is registered in react-scripts’ default webpack config, but a registered loader rule isn’t the same as one that ever runs. Checked properly this time: zero .svg files are imported anywhere in the project, and the shipped bundle has no .svg assets and no svgo/nth-check code signatures. serialize-javascript, flagged the same way in the same earlier pass, stays excluded on its own merits: traced into terser-webpack-plugin’s actual per-file transform, an unconditional part of every production minification pass – #78, merged
  • webtools: re-examine the 20 alerts still open after #78 rather than accept old verdicts at face value – two catch real mistakes in prior reasoning, two are genuinely new, one closes two overlapping advisories at once. tmp and flatted bumped further along already-forced chains, correcting a prior PR’s wrong reachability claim for flatted along the way (the real chain is eslint’s --cache option, never enabled here, not the inquirer path previously cited – the earlier conclusion was right, the stated reason wasn’t). fast-xml-parser, a new alert introduced by #78’s own is-svg bump, triple-unreachable. react-dev-utils, a real cross-major override whose vulnerable OS-command-injection function only runs from a start.js path this Docker build never takes – every export the production build path consumes diffed clean between versions. serialize-javascript, the one package here already proven actively reachable, closing two overlapping advisories at once, verified by diffing actual bundle bytes rather than just content hashes. postcss deliberately stays excluded, and this time proven rather than assumed: forcing it fails the build immediately with a real TypeError, a hard toolchain wall needing a CRA5 migration, not a theoretical one – #79, merged
  • webtools: two new alerts appeared within a minute of #79 merging – same pattern as fast-xml-parser following #78, a version bump’s own transitive tree landing right after the change that triggered it. immer (critical, prototype pollution), introduced by react-dev-utils@11.0.4’s own dependency tree; traced to its one real call site, which returns before reaching immer on this TypeScript-free app, but forced to the patched version anyway rather than left as another documented exclusion. serialize-javascript bumped once more (7.0.3 to 7.1.0) for a CPU-exhaustion DoS alert sitting inside the prior patched floor – re-verified the shipped bundle’s content hash, stable since #70, is unchanged – #80, merged
  • Retire a third-party FFmpeg fork frozen since 2020 (EnvelopSound/ffmpeg@earshot-v0.1, roughly 26k commits behind upstream) and build from the current n7.1 release tag instead. The fork existed for one reason – PCE-aware 16-channel AAC, needed to carry a hexadecagonal OBS Music Edition contribution through the RTMP leg – and both halves of that now check out natively: decode already ran unmodified on stock ffmpeg, and encode is native in n7.1’s aac_pce_configs[] (deliberately targeting n7.1 rather than a newer tag, since that layout was dropped from master in a later channel-layout API rework). Beyond retiring a stale fork, this closes roughly six years of hardening on exactly the demuxer and decoder paths that meet contribution bytes, and fixes a real interop bug: the 2020 muxer forced a mixed fMP4-video/WebM-audio manifest that stutters in FFmpeg-based players, where n7.1 can mux Opus-in-fMP4 properly for a single-container DASH manifest. Verified on real amd64 and native Raspberry Pi 4 arm64 builds, including a full synthetic 16-channel pipeline playing in-browser on Chrome and Firefox – #81, merged
  • A follow-up to #81: that PR fetched FFmpeg 7.1 from GitHub’s /archive/refs/tags/ URL, a tarball generated on demand whose bytes aren’t guaranteed stable, so nothing meaningful could be pinned against it. Switches the source to the signed ffmpeg.org release tarball instead, verified against a pinned SHA-256 before extraction – the hash itself checked against FFmpeg’s release-signing GPG key before being hardcoded, and a deliberately corrupted pin confirmed to fail the build at the checksum step, before extraction, rather than silently compiling unexpected source. Verified on real amd64 and native Raspberry Pi 4 arm64 builds, checksum passing on both – #82, merged
  • webtools: document why the AudioContext.resume() from #64 is needed, with the measurement – browsers construct video.js’s AudioContext at module-import time, before any user gesture, so an autoplay policy hands it back suspended and the whole graph stays silent regardless of gain or mute state. RMS-measured, isolating each step: gain alone and unmuting both read 0.0, only resume() makes it audible. Comment only, no behaviour change – a bare resume() with no explanation reads as defensive boilerplate and invites removal – #83, merged
  • /nginxInfo: report dashName alongside ffmpegFlags, so a client has a reliable way to know which manifest URL to request – DASH_NAME is configurable and need not match the publish name – #84, merged

thomasdeppisch/hoast360

  • Resume the AudioContext on the combined-MPD path, which was silent on every browser enforcing the autoplay policy – #30, merged
  • HoastLoader.concatBuffers() reads source channel 0 for every destination in a higher-order group, so 10 of 12 third-order filter channels load the wrong decoding filter – #31, merged
  • Gate on a real Opus decode – decodeAudioData on an OfflineAudioContext, which needs no user gesture and no MediaSource – instead of an advisory canPlayType/isTypeSupported check that a browser can pass and then still fail to decode; separates the Chrome DirectOpusAudioDecoding field-trial failure from a browser with no usable Opus decode at all, and names the flag that restores playback – #32, merged
  • Compensate the video edit list Chromium and Safari drop under MSE, a constant A/V offset with no error – the same finding already filed against Chromium, WebKit, Firefox and W3C, this time arguing for a player-side fix specifically, since HOAST360 feeds video through MSE and the source-side avoidance already contributed to Earshot (#53) only helps deployments that use it. Includes a working implementation, gated to the affected engines, already running in a fork (SegmentAudioFeed.js) – offered as a PR if wanted – #33, open, unconfirmed by the maintainer
  • Read the ambisonic order from the manifest when none is given – initialize() now reads it from the DASH manifest’s AudioChannelConfiguration when the argument is omitted, computing channels as (order + 1)^2; explicit orders still work and skip the fetch, so this is additive. orderFromManifest() exposed as a static, returning null rather than guessing when the manifest can’t be fetched or reports a channel count that isn’t a full ambisonic set. Used in production on a live 16-channel stream and 4- and 25-channel on-demand clips – #34, merged
  • Add addCaptions() for WebVTT subtitle tracks, handling three silent failure modes found the hard way: addRemoteTextTrack doesn’t exist until video.js finishes setup, so a call right after initialize() is simply lost; a cross-origin .vtt drops with no console error unless the media element carries crossorigin="anonymous"; and adding a track doesn’t display it – track.mode has to be set to 'showing' explicitly, the default flag alone doesn’t do it. crossOrigin is opt-in so it’s not a behaviour change for same-origin deployments – #35, merged

thomasdeppisch/videojs-xr

  • Mobile orientation controls, renderer sizing and a three.js deprecation: Math.clamp does not exist, rotateLeft/rotateUp are never exposed on the OrbitControls instance so the render loop dies on any device with an orientation sensor, and the mono renderer is never resized after a zero-size init – #28, open, unconfirmed by the maintainer

Dash-Industry-Forum/dash.js

  • Two unguarded reads that throw on input the player can legitimately be handed: a SegmentTimeline that may carry no S elements (both functions now report “nothing available yet” rather than throwing), and the non-ISOBMFF path – WebM segments carry no moof/mfhd, so the caption extractor’s crash was really BoxParser.getSamplesInfo failing upstream of it. Same shape as an already-merged fix for manifests with no Periods: fail soft on input that should not reach the parser. Four unit tests added, all failing on development and passing with the change – #5104, open, milestoned for 5.2.2, review requested by a dash.js maintainer
  • ManagedMediaSource: detaching the source latches the scheduler off permanently, so playback never restarts – when the media element’s load algorithm runs outside dash.js’s control (an external element.load(), a src write, or a UA-driven reload), the attached ManagedMediaSource closes permanently and emits endstreaming on the way out; ScheduleController’s request gate latches off with nothing left to reopen it, so the player sits at zero segment requests forever with no error anywhere. Deterministic and reproducible with no iPhone at all – element.removeAttribute('src'); element.load() at sourceopen reproduces it on any public DASH stream in seconds. dash.js’s own StreamController reaches this exact state itself via detachMediaSource(); hls.js hit the identical WebKit event years ago and already guards its handler against it – #5127, open
  • Fix for the above: StreamController now detects the external detach via the element’s emptied event and recovers the way its own decode-error handling already does, resuming from the last known position; MediaSourceController no longer lets a closing source’s stray events latch the scheduler. Verified in real Safari recovering full playback within tens of milliseconds of the detach – #5128, open

Browsers and standards

MSE empty-edit presentation offset – the same underlying finding, filed against every engine it touches. Each one turned out to be inconsistent in its own direction; see the engineering write-up for the technical detail.

  • Chromium – drops the offset in MSE, applies it in progressive <video src> playback – 537235698, open, engaged
  • Firefox (Mozilla) – the mirror image: applies the offset in MSE, drops it in progressive <video src> playback – 2056945, open (unconfirmed, awaiting triage)
  • Safari (WebKit) – same inconsistency as Chromium’s – 319998, closed as a duplicate: already fixed by unrelated work (bug 316870)
  • w3c/media-source – spec-clarification issue on the same divergence – #377, open

Multichannel Opus decode regression – a Chrome 151 field trial, DirectOpusAudioDecoding, breaks every Opus decode above 2 channels in both decodeAudioData and MSE playback.

WebKit

  • A tab can reach a state where nothing it plays is audible – Web Audio, <video>, everything – while every API reports success: AudioContext.state stays running, an analyser node confirms real samples reaching the destination, play() even resolves on a plain <audio> element. No page-observable signal distinguishes it from a working tab. Isolated to a bare test page with no player code, ruling out this stack’s own audio graph; reproduced across iOS 18.7 and an iOS 27 beta on the same device and independently confirmed by a second developer on a different one. Follows a specific pattern – entered via back/forward navigation within a tab, cleared only by an address-bar navigation or by quitting Safari, never by a reload – documented with three annotated snapshots and full steps to reproduce. Triaged into WebKit’s Media component and CC’d to WebKit media engineers including Jer Noble, then root-caused in WebKit’s own source: a GPU-process relaunch leaves the cached audio-session category stale, and the fresh GPU-side session defaults to a category iOS hard-mutes at the Ring/Silent switch while rendering keeps running underneath it – confirmed directly by flipping the physical switch, which restores and re-mutes audio with no reload. A page-side workaround follows from the same mechanism: cycling navigator.audioSession.type through a different value and back to 'playback' forces WebKit to resend the category and heals the session in place – 323104, open

Capture and encoding

pkviet/obs-studio

  • The hexadecagonal (16-channel) format disappeared from audio device properties in 27.0.x – #66, closed
  • 20-channel audio streaming – #67, closed
  • Failed to create audio encoder on the advanced output – #70, closed
  • Virtual camera installation – #71, open

ittiam-systems/libmpeghe

  • ffmpeg compilation for MPEG-H 3D Audio support – #8, open

m-ab-s/media-autobuild_suite

  • Request: MPEG-H 3D Audio – #2654, open, unconfirmed by the maintainer (community discussion only)

GyanD/codexffmpeg

  • MPEG-H 3D Audio – #128, closed

lsp-plugins/lsp-plugins

  • Windows 10 build stops with 'test' is not recognized#382, closed

FFmpeg/FFmpeg

  • aacenc: no channel layout above 8 channels can be encoded since a channel-layout API rework dropped the last >8-channel PCE table entry – a regression bisected to a single commit (11 steps, FFmpeg 8.1 good, master bad), and the same one Earshot #81 pinned to n7.1 specifically to avoid. Not a request to revert the removal (the dropped entries may genuinely have been non-compliant); asks for some path to encode discrete >8-channel audio to be restored, since third-order Ambisonics (16 channels, ACN/SN3D) has no positional layout that describes it correctly regardless of which one is picked – a discrete N-channel PCE with no positional claim would cover it and any other non-speaker use. James Almer – the regression’s original author – replied within a day with a fix restoring >8-channel PCE layouts at 4, 9 and 16 channels, using 9.1.6 rather than reintroducing HEXADECAGONAL, which defines two channels AAC doesn’t use. The 9-channel entry carries a direct contribution back: the channel reorder map ({2,5,6,0,1,7,8,3,4}) was measured here and adopted verbatim into the fix. 25 channels wasn’t added, so 4th-order Ambisonics still has no AAC route, and no release carries the fix yet – #24218, closed, fixed by ed923a7a89 and f35acb72ac

shaka-project/shaka-packager

  • OpusSpecific::ReadWriteInternal copies the RFC 7845 OpusHead body into the ISO BMFF dOps box verbatim, but OpusHead stores PreSkip, InputSampleRate and OutputGain little-endian while dOps requires big-endian – so a structurally valid box comes out with byte-reversed numbers (a 48 kHz stream reports InputSampleRate as 2159738880). Chromium’s MSE parser refuses the segment; plain <video src> playback is unaffected, which is likely why it survived since 2016. Only surfaces packaging Opus from WebM into MP4 – an existing Opus MP4 comes out looking correct, because the read path has the mirror defect and the two errors cancel exactly. The project’s own committed golden test file carries the malformed box, so its test suite requires the corruption to pass. Patch written and verified against their unit tests and Chromium’s MSE parser; offered to open a PR – #1627, open, unconfirmed by the maintainer

Infrastructure and networking

Found running a studio monitoring stack and a Raspberry Pi streaming node.

netalertx/NetAlertX

  • A device with a nic-typed parent gets an endless one-directional Connected/Disconnected event stream instead of tracking its own presence – #1736, fixed, released in v26.9.0
  • Skip Repeated Notifications is silently inert in most timezones, a UTC/localtime mismatch in the cooldown comparison – #1737, fixed, released in v26.9.0
  • A device’s free-text devComments containing a bare < crashes the whole notification build, silently dropping every pending alert in that cycle – #1743, fixed, released in v26.9.0

tailscale/tailscale

  • tailscaled SIGBUS on 32-bit ARM during an ML-KEM (X25519MLKEM768) TLS handshake – #20827, open, unconfirmed by the maintainer. A community write-up of the practical fix is under Community and hardware.

gnuton/asuswrt-merlin.ng

  • Access Restrictions’ SSH checkbox generates RETURN instead of ACCEPT, so the rule does nothing – #989, open, unconfirmed by the maintainer

raspberrypi/firmware

  • pwm-gpio-fan overlay: fan_temp1/fan_temp2/fan_temp3 trip-point overrides silently dropped at real boot, while fan_temp0 and all four fan_tempN_speed overrides apply correctly – isolated to the firmware’s config.txt-time parser specifically, not the overlay source or the dtmerge tool: merging the identical overlay and parameters offline reproduces the correct trip points, so the discrepancy is specific to whatever parses the dtoverlay= line at real boot. Cross-referenced a similar-symptom prior issue (a PoE HAT fan overlay) as related precedent without assuming it’s the same root cause, since that one involved an auto-loaded overlay race that doesn’t obviously apply here – #2041, open, corroborated by another user, no maintainer reply yet

gvigroux/hon

  • Haier’s cloud backend started rejecting POST /unified-api/v1/view/appliance-list with a structured MissingRequiredParameter/FunctionName error instead of the normal response – HTTP 200, auth accepted (no 401/403), so it’s a rejection of the request shape itself, not a credentials problem. Ruled out two candidate client-side fixes before reporting: adding the x-api-key header present in other hOn reimplementations but not this one, and adding a full block of x-hon-* device-identity headers from another reimplementation, both produced the byte-for-byte identical error, pointing at a change in Haier’s own backend routing rather than anything fixable client-side. Flagged, without assuming it’s the same bug, a same-week report of the official app itself losing command capability while reads still worked – a narrower symptom than this one, where reads fail outright – #353, open, unconfirmed by the maintainer

Statistics and plotting

goodekat/ggResidpanel

  • missing value where TRUE/FALSE needed#15, open, unconfirmed by the maintainer

chrimaho/PlottingNPS

  • Counting zero occurrences of promoters, passives and detractors – #1, open, unconfirmed by the maintainer

Desktop software

Mozilla Thunderbird

  • Hangs indefinitely at startup on macOS when the profile’s credential-store files (cert9.db, key4.db, logins.json, logins-backup.json, logins.db) are corrupted – a live stack sample shows the main thread and two NSS certificate-verification worker threads permanently blocked on a condition variable during startup, with no error and no timeout. Moving the corrupted files aside and letting Thunderbird regenerate them fixed it; full sample attached – 2069597, open, unconfirmed

Community and hardware

Not an issue tracker, but the same pattern: hit a wall, worked out why, shared the fix.

Seeed Studio Grove Water Level Sensor

  • The official library was Arduino-only; wrote and shared a working MicroPython port for Raspberry Pi, with a demo video. Seeed’s own staff asked to adopt it into their wiki – forum thread, shared

Asuswrt-Merlin community (SNBForums)

  • A persistent, working Tailscale setup for 32-bit ARM Merlin firmware (RT-AX58U_V2, gnuton fork), including the fix for the SIGBUS crash reported as tailscale/tailscale#20827 above – forum thread, shared