Troubleshooting
When something breaks
Sorted by what you see. Start with owfeed doctor or
owlab doctor — both print numbered findings that say what failed, the command that
failed, and what to do.
Installing on a router
| What you see | Cause and fix |
UNTRUSTED signature after a firmware upgrade | The key is gone. /etc/apk/keys/*.pem does not survive sysupgrade on its own. Re-add the key, then list it and your repository file in /lib/upgrade/keep.d/<feed>, which sysupgrade reads alongside /etc/sysupgrade.conf. |
apk asks for --allow-untrusted | The index is not signed by any key the router trusts. Check the key file is in /etc/apk/keys/ and that you are pointing at the right feed. Do not pass the flag — it disables the check you installed the key for. |
| Nothing downloads, HTTPS fails | A stock image cannot fetch over HTTPS. apk add ca-bundle libustream-mbedtls first. |
| The feed URL 404s or returns nothing | apk does not follow redirects (openwrt#17180). If the feed moved, put the final URL in the repository file. For apk the URL is the index file; for opkg it is the directory. |
| Your package never upgrades | It was installed from a file. apk add ./file.apk pins the content hash in /etc/apk/world, and that survives sysupgrade. Remove the package, add the repository, install by name. |
| Packages vanished after Attended Sysupgrade | Expected. owut forwards no custom repositories and the server's repository_allow_list is empty by default. Re-add the feed and reinstall. |
breaks: world[...] on every install | The rootfs and the feed are different point releases. Pin both to the same exact release. |
Building and packaging
| What you see | Cause and fix |
| apk rejects the package as uninstallable | arch: all. apk requires noarch. Use LUCI_PKGARCH:=all in a Makefile and let the build translate it, or write arch: noarch in owfeed.yml. |
| The key is refused | A PKCS#8 PEM. openssl genpkey -algorithm EC writes the wrong shape; only SEC1 works. Generate with owfeed keygen. |
| The version is rejected | After ~ apk reads a commit hash, so only hex digits are allowed. Write 1.0_beta1, not 1.0~beta. -r<n> goes last. |
| The index does not match the packages | You indexed before signing. Signing appends bytes. Run sign, then index. |
| Translations do not appear | LuCI reads compiled .lmo and ignores .po. Point i18n.from: at your catalogues and owfeed compiles them. |
| A user's settings are replaced on every upgrade | The file is shipped but not in conffiles:. Declare every /etc/config/* the package installs. |
| Works unminified, breaks after a real build | luci.mk minifies JS and CSS; owlab sync does not. Run owlab build before releasing. |
| A package is missing from one release line | owfeed doctor reads the tree and cannot see what was never written. Compare the built tree against your config — that is what a feed's own tree check is for. |
Publishing a feed
| What you see | Cause and fix |
$OWFEED_SIGN_KEY is empty | The secret is missing, or the job started before it existed. Note that a calling workflow cannot read an environment secret — signing secrets have to be repository or organization secrets. |
| OWF513: a published version has different contents | A package changed without a version bump, or the build stopped being reproducible. Do not publish over it. Bump the revision. |
OWF514: the live site lost .nojekyll | actions/upload-pages-artifact drops dotfiles from v4. Set include-hidden-files: true, or Pages runs Jekyll over your feed and deletes every path starting with a dot or underscore. |
| Pages deploy fails on permissions | actions/deploy-pages needs actions: read, which a permissions: block silently withholds by naming other scopes. |
owfeed doctor passes but smoke fails | The tree is coherent and a router still will not take it. Read the container output: usually a dependency that does not resolve on a stock image, or a file installed where nothing looks. |
| A documented install URL 404s | Your README drifted from the feed. Generate it: owfeed install-snippet. doctor compares the two. |
| The build fails on a stale lock | Upstream added or removed an architecture. Run owfeed lock --update and read the diff before committing it. |
Test routers (owlab)
| What you see | Cause and fix |
| LuCI answers but nothing works | procd jails services and a container cannot build a jail. Use fidelity: vm for anything that needs a real kernel or a jailed service. |
| A page returns 403 on a healthy router | An unauthenticated request to /cgi-bin/luci/admin is a redirect to the login form. owlab test logs in first; a hand-written curl does not. |
| HTTP 200 with a traceback in the body | LuCI's dispatcher answers 200 when it catches an exception. owlab test fails this; a status-code check does not. |
kmod-* installs but does not load | A container shares the host kernel. Kernel modules need fidelity: vm. |
| Installs start failing a day after they worked | You pinned snapshot. Snapshot images and snapshot feeds are rebuilt daily and independently. Pin exact point releases. |
Editing files under images/ changes nothing | The build context is embedded in the binary. Run go build again. |
| DNS is broken but the network is fine | The container engine does not forward outbound UDP 53. owlab doctor checks this. |
Where to look next