Skip to content

Editing a registered server's settings in darling.json is silently ignored — only ADDING a server is warned about #2552

Description

@erikdarlingdata

Found while standing up a live PostgreSQL target against a container build of dev.

What happens

WarnAboutFileOnlyServersAsync reads SELECT server_id, name FROM config_monitored_servers and compares names and ids only. If every server in darling.json is already registered, fileOnly.Count == 0 and it returns immediately. Nothing anywhere compares the file's per-server settings against the store's — grep for a property-drift comparison in StoreConfigProvider.cs finds none.

So for a server that is already registered, every setting in darling.json is dead text: trustServerCertificate, username, password, port, database, encryptMode, excludedDatabases, capturePlans, displayName. The file is read, parsed, validated, logged as Loaded configuration from /config/darling.json: 1 server(s) — and then the store's row is used instead, with no indication that the two disagree.

Why this is worse than it sounds

#2252/#2254 already warn — well — about the adjacent case:

darling.json lists N server(s) that are NOT monitored and never have been … The store is authoritative after the first seed, so adding a server to the file does not register it and a restart cannot change that

An operator who reads that learns "adding via the file does not work." The natural inference is that the file does still drive the servers it already knows about. It does not, and nothing corrects that inference.

The web.network / mcp.network blocks each log a full paragraph explaining they are file-only and restart-only and that the control plane owns the rest. The server list — far more likely to be edited than either — says nothing.

How I hit it, which is the realistic path

  1. Added a PostgreSQL target. First connect failed: [pgtarget] Connect failed, retrying in 60s: SSL connection requested. No SSL enabled connection from this host is configured. Good message — names the target and the cause.
  2. Enabled TLS on the target. Now: Exception while performing SSL handshake (self-signed cert, so SslMode.VerifyFull correctly refuses).
  3. Applied the documented fix — set "trustServerCertificate": true in darling.json — and restarted.
  4. Byte-identical error. No new information, no hint the edit was not read.

The store row explained it:

name     | trust_server_certificate |         created_at         |        modified_at
pgtarget | f                        | 2026-08-22 22:27:15.069708 | 2026-08-22 22:27:15.069708

created_at == modified_at, still f. The edit never left the file.

That is a bad loop to be stuck in: a connection failure is exactly the kind of problem an operator fixes by editing config and restarting, and this is the one class of edit that produces an unchanged error with no explanation.

Worth deciding, not assumed

I am not proposing that the file start overriding the store — store-authoritative is a deliberate design and #2254 is explicit about it. The gap is that the disagreement is invisible. The minimum fix is to extend the existing warning to cover servers present in both, comparing the settings that actually affect behaviour and naming the ones that differ, in the same voice as the existing message: what the file says, what the store says, and that the store wins and how to change it (Viewer's Add/Edit Server, or MCP add_servers).

Two things to settle first:

  • Which fields count. Comparing everything invites noise from cosmetic normalization — encrypt_mode is already normalized on seed (StoreConfigProvider.cs:350 mirrors the normalizer precisely so a casing choice cannot fail the seed), so a naive comparison would warn on a difference that does not exist. The comparison has to run against the same normalizer.
  • Passwords must not be compared or printed. The file may carry a file:/env: reference while the store carries a DPAPI blob; those are not comparable and the answer is almost certainly to exclude the credential from the drift check entirely rather than to try.

A --test-connection caveat probably belongs here too: per the #2252 message it already reads darling.json and reports PASS for servers that collect nothing. The same is true for settings — it would test the file's trustServerCertificate, not the store's, so it can report PASS for a configuration the service will never use.

Related: #2252, #2254, #2258.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions