Skip to content

fix(config): stop a partial POST /api/config from clearing omitted sections - #363

Draft
Davixk wants to merge 1 commit into
sirrobot01:betafrom
Davixk:fix/config-api-partial-post-preserves-sections
Draft

Davixk wants to merge 1 commit into
sirrobot01:betafrom
Davixk:fix/config-api-partial-post-preserves-sections

Conversation

@Davixk

@Davixk Davixk commented Jul 26, 2026

Copy link
Copy Markdown

What breaks: a POST /api/config body that omits a top-level section deletes that section from disk. Posting only {"log_level":"debug"} wipes debrids — configured providers and their api keys included — along with every other key the caller didn't mention.

Why: handleUpdateConfig in pkg/server/api.go decodes the body into a zero config.Config, so any absent top-level key ends up as its zero value, and the subsequent newConfig.Save() writes that zero value out.

The fix: merge on missing. Config.PreserveMissingSections copies every top-level section whose JSON key is absent from the posted body out of the live config before validation and save. Presence still wins wholesale, so an explicitly posted empty value ("debrids": []) clears exactly as before, and full-config POSTs (the web UI path) decode identically with and without the merge — there's a test asserting that.

Evidence: running in production on a ~47,000-entry library. Tests cover partial / explicit-empty / full POSTs at both the merge layer and the HTTP handler (asserting on-disk state); the partial-POST tests fail on beta without the change.

Split out of a second config-API fix (explicit download_uncached: false not persisting) so each is reviewable on its own; the two are independent.

…ctions

handleUpdateConfig decoded the request body into a zero config.Config, so any
top-level key missing from the request (e.g. no "debrids") was silently
replaced with its zero value and Save erased the section from disk. A caller
that posted only the field it wanted to change destroyed every other
configured section, including debrid providers and their api keys.

The handler now merges on missing: Config.PreserveMissingSections copies every
top-level section whose JSON key is absent from the posted body out of the live
config. Presence still wins wholesale, so an explicitly posted empty value
("debrids": []) clears exactly as before, and full-config POSTs (the web UI
path) are byte-identical in behavior.

Tests cover partial / explicit-empty / full POSTs at both the merge layer and
the HTTP handler (asserting on-disk state).
@Davixk
Davixk marked this pull request as draft July 26, 2026 14:07
@Davixk

Davixk commented Jul 26, 2026

Copy link
Copy Markdown
Author

Marking this draft — the fix is right but the verb is wrong, and I'd rather correct that than have you review it as-is.

Making POST merge is really just PATCH semantics under the wrong verb. I'm reworking this to expose PATCH (partial merge) and PUT (full replace) with honest contracts, keeping POST as a deprecated alias so existing clients don't break. Will un-draft once that's in.

Davixk added a commit to Davixk/decypharr that referenced this pull request Jul 26, 2026
Two corrections.

The "deliberately fork-only" section was mostly me deciding on the
maintainer's behalf what they would not want. That is not our call. The
repair model, the deletion cap and the read-deadline are queued to be
offered; only genuinely incident-specific tooling stays fork-only.

Adds a branch map, since "which branch is real" was ambiguous enough to
have already cost a wrong analysis: integration/v2 is canonical and is
what CI builds from, fixup/* are the handles upstream PRs get cherry-
picked from, and a fix/* branch backing an open PR is based on
upstream/beta and must never be merged back.

Also records that sirrobot01#363 proposes the wrong shape — making POST merge is
PATCH semantics under the wrong verb — and is superseded by a proper
PATCH/PUT split.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Davixk
Davixk force-pushed the fix/config-api-partial-post-preserves-sections branch from 8a7f489 to af29c72 Compare July 27, 2026 00:23

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant