Skip to content

Apply fails with UNIQUE constraint failed: owned_sections on a multi-radio wiphy (Tenda BE12 Pro / MT7996): both bands render as radio0 #39

Closed

Description

@flubba

Summary

On a Wi-Fi 7 router whose 2.4 GHz and 5 GHz radios share one wiphy, a WLAN on both bands is rendered into the same UCI section. Only one band comes up on the router, and the Apply stops with an ownership-recording error.

Environment

  • oonfeeWRT v0.1.5 (container); code path unchanged in v0.1.7, see below
  • Tenda BE12 Pro, mediatek/filogic, OpenWrt SNAPSHOT r35063-7edb29d241
  • Device mode: Managed

Steps to reproduce

  1. Adopt the BE12 Pro as a managed device.
  2. Create a WLAN on 2.4 GHz and 5 GHz.
  3. Preview → Apply.

Actual result

The Apply stops after this device:

Stopped after <device>: device outcome was applied, but controller ownership recording failed:
reconcile: applied but could not record ownership: store: record ownership claim: constraint failed:
UNIQUE constraint failed: owned_sections.device_id, owned_sections.config, owned_sections.section (1555)

On the router only one of the two bands was up afterwards.

Expected result

One wifi-iface per UCI radio (oowrt_wlanN_radio0 on radio0, oowrt_wlanN_radio1 on radio1), both bands up, Apply completes.

Cause

radioSection() in internal/render/render.go derives the UCI wifi-device from the phy index (phy0 → radio0). On this board both radios are served by one wiphy:

$ iw dev
phy#0
	Interface phy0.1-ap0
		channel 52 (5260 MHz), width: 80 MHz
	Interface phy0.0-ap0
		channel 1 (2412 MHz), width: 20 MHz
radio0  band=2g  radio=0  path=soc/11280000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0
radio1  band=5g  radio=1  path=soc/11280000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0

Both interfaces report phy0, so both bands map to radio0 and render a section with the same name. The router ends up with one of them, and recording ownership of the second fails on the unique index.

Suggested fix

luci-rpc.getWirelessDevices, which the capability probe already reads, is keyed by the UCI radio section. Keeping that key on capability.Radio (for example as Section) and preferring it in radioSection() fixes this, with the phy derivation kept as a fallback for capability records stored before the field existed. An already adopted device then needs one re-probe.

I have this change with tests (a render test for a two-radio wiphy, a probe test that each radio keeps its UCI section). It applies cleanly on current main (v0.1.7) and go test ./... passes there. With the patched build, re-probe and Apply on the BE12 Pro work and both bands are up. I'm happy to open a PR if that's useful to you, or you can take the idea as it is.

How this report was made

I use AI tooling and want to be clear about who did what:

  • Me: running oonfeeWRT with three OpenWrt APs at home, hitting the failure in the UI, reviewing the patch, deploying the patched build, re-probing and applying, and confirming on the real BE12 Pro that both bands come up and Apply completes.
  • Claude Code (Anthropic): tracing the error to radioSection(), reading the router output above, writing the patch and tests, rebasing onto main and running the test suite, and drafting this issue.
  • Not verified: v0.1.7 on hardware. The build I run is v0.1.5 plus this fix; for v0.1.7 I checked that radioSection() is unchanged and that the patch applies cleanly with passing tests.

Activity

  1. self-assigned this
    on Sep 17, 2026
  2. aiden0rchad commented on Sep 17, 2026

    @aiden0rchad
    Owner

    Great job filing this report, I dont mind that your agent filed this report for you, It gave a very detail report. I'm currently testing solutions at the moment, I dont exactly have the same hardware but if you wouldnt mind testing out a build and verifying if works. If it does, do let me know and I will be pushing it to main asap

  3. aiden0rchad commented on Sep 17, 2026

    @aiden0rchad
    Owner

    Following up with the proposed fix: #42 (commit b3b7adfec9549c901c72601f49bada8a1e96ec5e). Thanks @flubba for the detailed diagnosis and the UCI-section approach.

    The patch retains each configured radio's UCI section even when both use phy0. It also rejects ambiguous saved radio mappings and duplicate desired sections before router writes or ownership recording. It does not work around the error by weakening the database constraint.

    The full capability, rendering, and reconciliation test suites, vet, and documentation build passed locally. Tests cover a two-band/shared-PHY probe, both distinct rendered targets, an idempotent next plan after a mock-backed Apply, and rejection of duplicates before side effects. Independent review is complete; GitHub's full CI is running on the PR.

    Could you verify this exact PR build on the BE12 Pro? Your existing hardware verification was on your own v0.1.5 patch; I have not tested this build on that hardware. The local wired lab connection is currently unavailable.

    Before testing, preserve your pre-upgrade recovery backup: this PR is based on v0.1.7, so upgrading from v0.1.5 still requires the normal upgrade precautions. Then Re-probe capabilities → Preview and check that the two bands have distinct UCI sections/device references. Only Apply if the preview is correct and it is safe to change the router. Please confirm both bands work and a subsequent Preview is clean.

    A previous failed Apply may already have changed the router; please don't reset the database, clear ownership records, or re-adopt as a workaround. If this build still fails, share sanitized re-probe/preview evidence and the exact error, without credentials or wireless keys. Leaving the issue open until you can verify.

  4. flubba commented on Sep 17, 2026

    @flubba
    Author

    Verified on the BE12 Pro. The PR build behaves correctly here.

    Build provenance

    • Built from codex/issue-39-shared-wiphy at b3b7adfec9549c901c72601f49bada8a1e96ec5e, no local modifications.
    • Image built with the repository's own deploy/Dockerfile, tagged v0.1.7-pr42-b3b7adf. Compose and environment unchanged from my previous deployment; only the image tag changed.

    Upgrade precautions

    • Previous deployment: my own v0.1.5 patch build, schema 23.
    • Controller stopped cleanly; data/ (database + keyring.json) and the runtime passphrase copied aside. Copy verified: identical SHA-256 for database, keyring and passphrase, PRAGMA integrity_check = ok, empty WAL, schema_version = 23. The v0.1.5 image is retained.
    • First start of this build migrated 23 → 25 without errors; container healthy, /healthz = 200, no warnings in the controller log other than one device being powered off (see below).

    Environment

    • Tenda BE12 Pro, mediatek/filogic, OpenWrt SNAPSHOT r35063-7edb29d241. Shared PHY: phy0.0-ap0 (2.4 GHz) and phy0.1-ap0 (5 GHz) both on phy0, configured as radio0 and radio1.
    • Same site: two single-PHY APs on OpenWrt 25.12.5, plus a Cudy TR1200 that is powered off outside cinema hours — it reports as unreachable throughout, which is expected and unrelated.

    Results

    1. Re-probe capabilities on the BE12 Pro: "Probed — nothing changed", class B. Controller log: capability probe found no changes device=0c:85:09:03:05:50 automatic=false. The stored radios are:
      • Device phy0.0-ap0, Phy phy0, Section radio0, band 2g, channel 1
      • Device phy0.1-ap0, Phy phy0, Section radio1, band 5g, channel 52
        Both on one PHY, with distinct UCI sections, hardware MediaTek MT7992E.
    2. Preview (taken three times: before the apply, again before the apply, and after it): 0 changes for every device, nothing blocked, no ambiguous-radio-target message, no demand to re-probe.
    3. Apply, scoped to the BE12 Pro: state completed, router_outcome: applied, outcome: applied, changes: 0, write_state: none, reason "already matches the site model; nothing to do", no error. No UNIQUE constraint failed: owned_sections — that is exactly where the original apply stopped.
    4. Ownership after the apply: exactly two rows for this device, wireless.oowrt_wlan2_radio0 and wireless.oowrt_wlan2_radio1 (8 rows for 4 devices, no duplicates).
    5. Router afterwards: both wifi-iface sections unchanged and referencing radio0 / radio1 respectively; both bands broadcasting (channel 1 with 10 clients, channel 52 with 8 clients); hostapd reports ENABLED on both BSSes; the apply triggered no hostapd or netifd events.

    One honest limitation

    My own v0.1.5 patch had already written the two correct sections to this router, so this build had nothing left to write. The run therefore exercised probing, rendering, validation, the apply path and ownership recording — but not a fresh write of the sections. What it does show is that the PR build renders the two bands to distinct UCI sections and agrees with a router that already has them: had it still collapsed both onto radio0, the preview would have proposed rewriting or dropping the second section, and it does not.

    If you want the write path exercised from a clean slate on this hardware, say so and I can arrange a controlled run.

    Verdict: confirmed working on the affected hardware. Thanks for the quick turnaround.

    Testing, evidence collection and this write-up done with Claude Code, same as the original report; the hardware runs, the re-probe and the apply were mine.

  5. aiden0rchad commented on Sep 18, 2026

    @aiden0rchad
    Owner

    v0.1.8 is now published with the shared-PHY radio-identity fix from #42: release and downloads.

    The prebuilt container is ghcr.io/aiden0rchad/oonfeewrt:v0.1.8 for Linux amd64/arm64; standalone Linux and macOS binaries are also attached to the release.

    Thank you, @flubba, for the detailed diagnosis and for verifying the exact PR build on the BE12 Pro. Your successful re-probe, repeated Preview, no-op Apply, and distinct ownership rows are valuable confirmation. That test used configuration corrected by your earlier patch, so we are not presenting it as a fresh-write hardware test. Our WRT3200ACM and Archer C6 checks were read-only and also proposed no changes.

    After taking the documented upgrade backup, please verify the official v0.1.8 build: re-probe the affected device, then generate a fresh Preview and confirm the distinct UCI radio targets. Apply only if the plan is intended and it is safe to change the router. There is no need to undo a working configuration just to test this release, clear ownership rows, reset the database, or re-adopt.

    Could you confirm whether the released build resolves this issue? If a normal, planned configuration change later exercises fresh writes on the shared-PHY device, that result would also be helpful. Please share any remaining error and sanitized probe/Preview evidence, without credentials, wireless keys, or network identifiers. Leaving this issue open pending your release verification.

  6. aiden0rchad commented on Sep 18, 2026

    @aiden0rchad
    Owner

    Thanks again, @flubba, for the detailed report and verification of the exact PR build. Closing the reported radio-target collapse and ownership-recording error as fixed by #42, now shipped in v0.1.8.

    The hardware evidence covers re-probe, Preview, no-op Apply, and distinct ownership records—not fresh configuration writes on shared-PHY hardware. That limitation remains documented; there is no need to undo a working setup solely for testing.

    If the problem persists on v0.1.8 after re-probing and reviewing a fresh Preview, please comment with sanitized evidence and we can reopen this issue. Do not reset the database or clear ownership records as a workaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions