Skip to content

Config not applying after save

You edited something in the UI, the save succeeded, and the collector carried on with its previous configuration. Work through these checks in order. Check 1 tells you whether the problem is in generation or in delivery, and the two have completely different fixes — so don’t skip it.

Check 1: does the generated config actually contain your change?

Section titled “Check 1: does the generated config actually contain your change?”

Open Collectors → your collector → Config. The config shown there is generated fresh when you open the tab, from the same generator that feeds the collector — so it is the authoritative answer to “what would this collector get right now?”

  • Your change is there. Generation is fine and this is a delivery problem. Continue with Check 2.
  • Your change is missing. Generation never picked it up, and pushing harder will not help. Skip to Check 5.
  • The tab is empty — no files at all. Generation failed. The tab renders what the generator returned, and on failure that is nothing. Skip to Check 5.

This is the single most common cause, and it is not obvious from the UI.

Saving a route, a source activation, or a destination activation re-pushes that collector’s config automatically in the background. Saving anything else does not.

In particular, editing a pipeline does not push it. Add a processor to a pipeline, change an OTTL statement, reorder a chain — the pipeline is saved, every route referencing it will use the new version the next time a config is generated, but nothing schedules that generation.

The fix is to trigger a push: open Collectors → your collector → Config and click Reapply Config. That regenerates and pushes to that one collector.

For the whole fleet, use Settings → Live → Re-push current config to all collectors instead — it pushes the live version to every collector rather than the one you are looking at, and it is audited.

Check 3: has the collector had time to pick it up?

Section titled “Check 3: has the collector had time to pick it up?”
Runtime How config arrives Expect it within
Grafana Alloy (remotecfg) Alloy polls and fetches the new body one poll interval — 60 seconds by default
otelcol-contrib (OpAMP) The server pushes; the supervisor restarts the collector with it seconds, once a push happens

An unchanged config returns not_modified, so a poll that finds nothing new costs effectively nothing — a collector that is polling normally is not “stuck”, it simply has nothing to fetch.

If a collector is offline, no push can reach it — but nothing is queued or lost either. An otelcol collector is pushed a freshly generated config when it reconnects, so it converges on current state rather than on whatever it missed.

That also makes restarting the collector a legitimate way out of a stuck pipeline edit: reconnecting triggers a fresh push. Reapply is the cheaper move, but if you have already restarted the collector for another reason, it has current config.

If the collector’s page shows Incompatible, LinkMesh is withholding the config on purpose: it needs a declared extension the collector’s binary doesn’t contain. Restarting doesn’t help. The collector keeps its last good config until the extension is removed or the collector runs a build that has it. See When a collector goes incompatible.

Check 4: did the collector reject the config?

Section titled “Check 4: did the collector reject the config?”

A collector can receive a config and refuse to apply it. Open Collectors → your collector → Events and look for:

  • config_rejected — the collector received the config and refused it. The event carries the collector’s own error message, which is the actual diagnosis. The collector’s status also goes to warning.
  • config_rolled_back — an otelcol collector refused a config at start, and LinkMesh sent it back the last config it had applied, so it is running again on that. The message names the cause in one line: a missing file, a port in use, a component the collector doesn’t have. Your change is not running there. Fix the cause, then save again or click Reapply Config to retry it. A collector that has never applied a config from LinkMesh has nothing to roll back to and keeps restarting on the failing one until the cause is removed.
  • config_applied — it worked. If this is present and newer than your edit, the collector is running your change and the problem is somewhere else (see Check 6).
  • config_drift_detected — the config running on the host no longer matches what the server sent, usually because someone edited the file on the host directly. For an otelcol collector this heals itself: the server re-pushes the desired config when it sees the drift, at most once a minute per collector. A drift event that keeps repeating means the collector is rejecting the pushed config rather than losing it — look for config_rejected alongside it. After a config_rolled_back the drift is expected and is not re-pushed on its own: the collector stays on its previous config until an edit, a Reapply Config or a reconnect.

A rejection is almost always the collector’s own config validation failing — an exporter that cannot resolve, a receiver bound to a port already in use, a processor the runtime does not have. The message in the event names it.

Check 5: did config generation fail on the server?

Section titled “Check 5: did config generation fail on the server?”

If Check 1 showed your change missing from the generated config, either the entity is not wired into anything that reaches this collector, or generation itself failed.

First, the wiring — a pipeline reaches a collector only through a route:

  • Is the pipeline attached to a route?
  • Is that route on this collector (or a group it belongs to)?
  • Are the route’s source and destination both activated on it?
  • Is the route enabled?

If the wiring is right, generation failed. This is worth knowing about because an automatic re-push is fire-and-forget: if generation fails, nothing surfaces in the UI. The save returns success, no event is emitted, and the collector keeps its old config. The Config tab shows an empty file list rather than a message, so the reason is only in the server log:

# single-host install
journalctl -u linkmesh-server | grep -i "config generation failed"

# Kubernetes
kubectl -n linkmesh logs deploy/linkmesh-server | grep -i "config generation failed"

Clicking Reapply Config after a generation failure is still useful: the reapply path surfaces failures the background push swallows.

Check 6: the config applied, but the behaviour didn’t change

Section titled “Check 6: the config applied, but the behaviour didn’t change”

If config_applied is present and current, the collector is running your configuration and the question is why it isn’t doing what you expected.

  • A processor step is in the chain but never fires. A masking or filter rule that matches nothing is indistinguishable from a working one from the outside — the pipeline looks configured and nothing reports a zero match count. Verify the rule against a record shaped like your real traffic in the dry-run panel, not against the shortest string that satisfies it.
  • The route filters the signal out. A route only carries the signal types it declares. A logs-only route will not move your metrics however correct the pipeline is — see Filter records on a route.
  • You are reading the wrong edge. If the numbers rather than the behaviour look wrong, that is a different symptom: Self-telemetry troubleshooting.