LinkMesh

Search docs, blog and changelog

ENDE

Changelog

What changed, and whether it breaks you.

Every release you can install, newest first. Breaking changes come first in each entry, with the steps to take before you upgrade — so you can decide without asking us. Upgrading is covered in the upgrade guide.

Read the marker, not the version number.

Version numbers do not carry a semver major warning: a breaking change can ship in a minor release. Rely on the breaking-change marker, not on the version number.

Subscribe to the feed to hear about a release instead of checking this page.

LinkMesh Server 1.399.3

Breaking changes

Permalink

LinkMesh is in Early Access and this release carries 28 breaking changes: read every upgrade note before you upgrade, and if you use single sign-on, read that note first. It adds custom OpenTelemetry sources and destinations with extensions that are checked before they can stop a collector, rolls a collector back when a pushed config fails, makes every save a version, and fixes the fleet view for groups, Kubernetes and restarts.

Breaking changes

This release contains breaking changes. Read the upgrade notes below before upgrading.

  1. Single sign-on (auth.mode=external) now requires an Enterprise licence. On a server with no licence file, a Community licence or a Read-only licence, new SSO sign-ins and external tokens are refused at once with 403 license_sso_required; SSO sessions that already exist end when their token expires, at most 24h after the upgrade. Local administrator password login always keeps working.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Only servers that use single sign-on (auth.mode=external) AND run with no licence file, a Community licence, or a Read-only licence. A paid or unlimited (Enterprise) licence in Active or Grace state keeps SSO exactly as before. Servers that do not use SSO are not affected.

    WHAT HAPPENS. New SSO sign-ins are refused immediately after the upgrade. SSO sessions created before the upgrade keep working until their token expires (auth.tokenExpiry, 24h by default), then end. SSO sessions created on this version end at once if the licence later lapses.

    BEFORE YOU UPGRADE, if you are affected:

    1. Confirm you can sign in with the LOCAL ADMINISTRATOR PASSWORD (the local admin account), not through your identity provider. Sign in with it once, now, on the version you run today. If you do not know it, reset it on the server host with linkmesh-server reset-password --email <admin email> (linkmesh-server list-users shows the local accounts). This step is what keeps you from being locked out: SSO sign-in is refused after the upgrade until an Enterprise licence is uploaded.
    2. Tell your SSO users that they cannot sign in again through SSO until step 4 is done, and that a session they already have ends within 24 hours of the upgrade.
    3. If SSO must keep working, obtain an Enterprise licence (https://linkmesh.io/pricing/) before you upgrade.

    AFTER YOU UPGRADE:

    1. Sign in with the local administrator password and upload the Enterprise licence under Settings -> License (or linkmesh-server license apply). SSO works again immediately, without a restart.
    2. Without an Enterprise licence, keep working with local accounts. Your SSO configuration and claim mappings are kept and can still be edited; they take effect again once an Enterprise licence is uploaded.

    HOW TO RECOGNISE IT: SSO sign-in fails with the code license_sso_required, and the login page says "Single sign-on requires an Enterprise license". The SSO claim-mapping screen carries an "Enterprise feature" badge.

  2. Every config save is now its own commit in the config repository, so the separate commit step is gone; publish no longer commits pending changes and only re-pushes the live commit; GET /settings/git returns liveSha instead of publishedSha; the production clone directory is no longer used.

    Written by us

    Before you upgrade

    BEFORE YOU UPGRADE:

    1. Optional: commit or discard pending changes on the version you run today. You do not have to: pending changes are not lost, because the upgrade itself records them as a version named "Snapshot at upgrade: N change(s) that were live but not yet in version history", authored by LinkMesh System.
    2. Back up the server's data directory (the bolt state file, or your MongoDB database) and the config repository directory. A downgrade back to an older release is not supported after this upgrade: older releases deploy from the production clone, which this release stops updating, so a downgraded server would push a stale configuration.

    AFTER YOU UPGRADE:

    1. Saving is live: each save becomes a version, authored by the user who saved. There is no separate "commit" step in the UI any more. If Version History shows a "Snapshot at upgrade" version, it holds the changes that were pending when you upgraded.
    2. Scripts: stop reading publishedSha from GET /settings/git; read liveSha (the commit your collectors run). POST /config-as-code/publish and /publish/{collectorId} no longer create a commit or pull a connected remote; they re-push the live commit and return liveSha. POST /config-as-code/rollback now accepts any commit in history and returns the target as sha plus liveSha, the new revert commit.
    3. If a save answers 500, the change is already live but was not recorded; record it with POST /config-as-code/commit.
    4. productionClonePath in your configuration is ignored and can be removed.
  3. On installs with a connected Git repository, the repository becomes a read-only mirror: Deploy no longer pulls from it and the Git webhook no longer applies commits, so changes made directly in the repository never reach collectors. A diverged remote refuses pushes until you overwrite it.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Only installs with a connected Git repository (Settings -> GitOps). Local-only installs are unaffected.

    THE MIRROR NEEDS AN ACCESS TOKEN ON THE REMOTE. Only an https remote configured with an access token is mirrored. A remote without a token (an SSH key or a local path) is not mirrored at all, and LinkMesh currently shows no warning about it. If you rely on the repository as a copy of LinkMesh's history, configure the remote as https with an access token.

    BEFORE YOU UPGRADE:

    1. Make sure every change you want is in LinkMesh: if anyone edits configuration directly in the repository, apply those edits in LinkMesh (or Deploy them on the current version) first. After the upgrade, commits made in the repository are never applied to collectors.
    2. Stop any process that writes to that repository (CI jobs, scripts, other people's pushes). Make changes in LinkMesh instead.

    AFTER YOU UPGRADE:

    1. Open Settings -> GitOps. If it shows "Remote mirror out of sync", the repository holds commits LinkMesh does not have and pushes are being refused. Re-apply any of those changes you want in LinkMesh, then use "Overwrite remote with LinkMesh history" (POST /api/v1/settings/git/mirror/force-push).
    2. Scripts: the pushed field of commit responses is now false whenever the push was refused, and commit, publish and rollback responses carry a new mirror object describing the remote's state.
  4. POST /config-as-code/rollback now answers 409 rollback_pending_changes while there are changes not yet in Version History, instead of silently discarding them.

    Written by us

    Before you upgrade

    Only API users and scripts are affected; the UI offers the choice itself. Before upgrading, find any automation that calls POST /config-as-code/rollback. After upgrading, such a call either records pending changes first (POST /config-as-code/commit), discards them, or sends "commitPending": true to record them as a snapshot version and roll back in one request. A script that relied on rollback discarding unrecorded changes must now discard them explicitly.

  5. Agents enrolled with a reusable Kubernetes fleet token now appear once per node, named after their pod, instead of as one shared "fleet:<fleetId>" entry; the old shared entry goes offline and is removed after fleet.reapAfter (default 24h).

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Installs with Kubernetes agents enrolled through a reusable fleet token. No action is needed before upgrading. After upgrading, expect the Agents page to show one entry per node, named after its pod; the old shared "fleet:<fleetId>" entry goes offline and disappears after fleet.reapAfter (default 24h), and each node's entry is removed the same way after its pod is replaced. Update any dashboard, alert or script that looked for the shared "fleet:<fleetId>" agent. On first start the server removes the default OTLP Input source and Default route it had written under collectors/fleet:<fleetId>/ (they configured nothing). Files there that you edited are kept.

  6. Behind a reverse proxy, the client IP in the audit log and the login throttle now comes from the X-Forwarded-For entry appended by the last proxy listed in http.trustedProxies; True-Client-IP is no longer honoured.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Servers behind one or more reverse proxies, load balancers or CDNs. BEFORE YOU UPGRADE: list EVERY proxy a request passes through in http.trustedProxies (for example both your CDN ranges and your nginx ingress). If one is missing, the outermost unlisted proxy's address is recorded instead of the user's, and the login throttle then counts all users behind that proxy as one client. AFTER YOU UPGRADE: sign in once and check in the Audit Log that your own address is recorded, not a proxy's. If you relied on True-Client-IP, configure your proxy to append X-Forwarded-For instead.

  7. Creating or editing a route whose destinationIds names a destination that is not activated on the route's collector (or its group, or for a group route on one of its members) is now refused with 400. Such a route never delivered anything.

    Written by us

    Before you upgrade

    Nothing changes for routes that work today. If a route save is refused after upgrading: activate the destination on the collector or group where the route runs, then reference that activation's id in the route. Scripts that create routes must reference destination activations on the same collector or group. Guide: https://linkmesh.io/docs/how-to/create-a-custom-source-or-destination/

  8. Assigning an HTTP Check or TCP Port Check source to a Kubernetes collector group with more than one member is now refused (400 port_check_on_kubernetes_fleet); it used to run the check once per pod and send identical series.

    Written by us

    Before you upgrade

    Checks already assigned to such a group keep running unchanged after the upgrade, still once per pod. To stop the duplicated series, remove the check from the multi-member Kubernetes group and assign it to a single-replica (Deployment) group or to one collector instead. The same refusal now also applies to the older POST /collector-groups/{id}/sources route.

  9. lockedByGroup in GET /api/v1/collectors/{id} no longer carries the group's full record; it now holds only id, groupId, name and kind.

    Written by us

    Before you upgrade

    Only API clients are affected. If a script read collectorIds, description or other group fields from lockedByGroup, read the group itself with GET /api/v1/collector-groups/{id} using lockedByGroup.groupId.

  10. GET /api/v1/collectors/{id}/events now returns 50 events per page by default instead of the newest 100, and answers 404 for an unknown collector instead of an empty list.

    Written by us

    Before you upgrade

    Only API clients are affected. Pass ?limit= (up to 200) and ?page=, or follow the Link header, to read further back. Treat 404 as "this collector does not exist" rather than expecting an empty list.

  11. GET /api/v1/sources/throughput and GET /api/v1/destinations/throughput now return data as an object keyed by entity id instead of an (always empty) array.

    Written by us

    Before you upgrade

    Only API clients are affected. A client that parsed data as an array must read it as a map keyed by source or destination id. The array was never populated, so no value was ever read from it.

  12. The destination setting auth_extension now means "authenticate through the declared extension with this label". A destination that carried a stray auth_extension key (until now ignored) is left out of collectors where that label is not declared and out of every Grafana Alloy collector; saving it beside basic_auth credentials or on a Kafka, File or Debug destination is refused.

    Written by us

    Before you upgrade

    BEFORE YOU UPGRADE: search your destinations for an auth_extension key (in the UI or via GET /api/v1/destinations). For each one, either remove the key, or plan to declare an authenticator extension with that label on every collector or group the destination runs on. AFTER YOU UPGRADE: check the config generation warnings for destinations that were left out, and confirm each destination still delivers. Do not combine auth_extension with basic_auth credentials; Kafka, File and Debug destinations cannot use it.

  13. An authenticator reference (a destination's auth_extension, or ${ext:<label>} under auth.authenticator in a custom body) must now resolve to an extension type that can authenticate that component; anything else is refused with extension_not_authenticator, and a stored one is left out of the collector's config with a warning.

    Written by us

    Before you upgrade

    After upgrading, check the config generation warnings. If a source or destination was left out with extension_not_authenticator, point its reference at a permitted authenticator extension (see "Which extensions can authenticate" in the collector extensions documentation) or clear the reference. Retyping an extension that is in use as an authenticator to a non-authenticator type is also refused.

  14. Saving a declared extension, or attaching a source, is refused with 400 (extension_port_in_use / source_port_in_use) when it would listen on a port another source or extension on the same collector already binds, including two extensions of the same type that both use the default port.

    Written by us

    Before you upgrade

    Such a configuration never started, so nothing that runs today stops. If a save is refused after upgrading, give one of the two a different port in its body or source config and save again.

  15. A custom destination whose stored config already carries durable_queue: true (previously ignored) now gets a disk-backed sending queue on its next config push; turning durable delivery on for a custom destination whose body sets sending_queue.storage, block_on_overflow, enabled: false or a conflicting queue_size is refused with 400 durable_queue_raw_body_conflict.

    Written by us

    Before you upgrade

    BEFORE YOU UPGRADE: check custom (raw-body) destinations for durable_queue: true. After the upgrade they start writing a persistent queue to disk on the collector; make sure the collector has a writable storage directory and disk space, or set durable_queue to false. AFTER YOU UPGRADE: if enabling durable delivery is refused with durable_queue_raw_body_conflict, keep only one of the two: either the Durable Delivery switch, or the sending_queue settings in the body.

  16. Attaching a custom (raw-body) source or destination to an OpenTelemetry Collector is refused with 422 component_not_on_collector when the collector's component inventory lacks that component, or its inventory is unknown and LinkMesh has no template for the type.

    Written by us

    Before you upgrade

    Already attached components keep running. If an attach is refused after upgrading, attach it to a collector whose version or reported component inventory includes that component (the collector page now shows its inventory), or upgrade the collector to a distribution that contains it.

    OPAMP COLLECTORS INSTALLED WITH AN OLDER SCRIPT. Collectors installed by an older install-opamp.sh keep reporting a static component list after the server upgrade, because their supervisor configuration (supervisor.yaml) does not ask the collector for its real inventory; only collectors enrolled on this version report it. Re-run install-opamp.sh on those hosts (or add the reports_available_components capability to their supervisor.yaml and restart the supervisor) so LinkMesh checks attaches against the collector's real component list.

    Guide: https://linkmesh.io/docs/how-to/create-a-custom-source-or-destination/

  17. Changing the receiver or exporter type of a custom (raw-body) source or destination that is attached to an OpenTelemetry Collector is refused with 422 component_not_on_collector when that collector lacks the new type, or its inventory is unknown and LinkMesh has no template for it.

    Written by us

    Before you upgrade

    If a retype is refused after upgrading, detach the source or destination from the collectors that lack the new component first, or pick a type those collectors contain.

  18. A custom (raw) source or destination body containing a value shaped like an OpenTelemetry Collector extension id (for example file_storage/x or bearertokenauth/y) is refused on save, and a stored one is left out of the generated config with a warning.

    Written by us

    Before you upgrade

    Extension ids are generated by LinkMesh, so such a value never named a working extension. After upgrading, check the config generation warnings; for each affected body, declare the extension on the collector or group and reference it as ${ext:<label>} instead of the literal id.

  19. A destination template with a custom body must now name its exporterType; one saved without it is refused (422) on its next save, including a rename.

    Written by us

    Before you upgrade

    After upgrading, when you next edit such a destination template, set exporterType to the exporter its body configures; the save is refused until you do. Templates you do not edit keep working.

  20. A custom source or destination body that sets a key its OpenTelemetry Collector component does not have is refused on save (400 raw_yaml_unknown_key), and a stored one is left out of the generated config with a warning.

    Written by us

    Before you upgrade

    Such a body made the collector reject its whole configuration and restart in a loop, so removing it lets the rest of the collector run. After upgrading, check the config generation warnings; fix the key's spelling or nesting level (the error names the path and the keys accepted there) and save again.

  21. A source or destination with a custom (raw) body that is attached to a Grafana Alloy collector is no longer rendered there (Alloy used to silently ignore the body and use the type's defaults); attaching one to an Alloy collector is refused.

    Written by us

    Before you upgrade

    BEFORE YOU UPGRADE: find custom-body sources and destinations attached to Grafana Alloy collectors. They were running with the type's defaults, not with your body; after the upgrade they stop running on Alloy and the config apply reports a warning. To keep them, move them to an OpenTelemetry Collector (OpAMP) collector, which renders the body as written, or replace them on Alloy with a built-in (non-custom) source or destination. In a group that mixes both runtimes, custom bodies are refused for the whole group.

  22. A source or destination custom body (rawYaml) that references a collector extension directly (auth.authenticator, a storage key, or a literal extension) is refused on save, and a stored one is left out of the generated config with a warning.

    Written by us

    Before you upgrade

    Such a body passed validation and then stopped the collector at start. After upgrading, check the config generation warnings. Declare the extension on the collector or group and reference it as ${ext:<label>} (or, for durable delivery on a custom destination, use the Durable Delivery switch), then save again.

  23. On Grafana Alloy collectors, journald sources now apply their Minimum Priority, which they used to ignore; a source set to or defaulting to info stops collecting debug entries there, and every journald source gets a new configuration on the next push.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. journald sources running on Grafana Alloy collectors. Before upgrading, decide whether you rely on debug entries from them. If you do, set Minimum Priority to debug on those sources (before or right after the upgrade). Expect lower log volume from Alloy journald sources otherwise; OpenTelemetry Collector journald sources already behaved this way.

  24. An HTTP Check source's timeout now takes effect: an endpoint that does not answer within the timeout (10s unless set) is reported down; a timeout without a unit (for example "10" or "0s") is refused on save.

    Written by us

    Before you upgrade

    BEFORE YOU UPGRADE: list HTTP Check sources that probe slow endpoints and raise their Timeout above the endpoint's normal response time; otherwise they start reporting the endpoint as down after the upgrade. Change any timeout written without a unit to a duration such as "10s", or the next save of that source or override is refused.

  25. A source receiverType or destination exporterType that no collector runtime can load is refused with 422 instead of stored (destination templates included); a stored activation with such a type is dropped from the collector's config and reported in the generation warnings.

    Written by us

    Before you upgrade

    Collectors that were crash-looping on such a component now start and run everything else, with that component absent. After upgrading, check the config generation warnings; if a source or destination stops reporting data, change its type to one the collector supports.

  26. A config push that needs an extension the collector does not have is no longer sent: the collector keeps its current configuration and is marked incompatible on its detail page.

    Written by us

    Before you upgrade

    Declared as breaking by product management, not by a commit footer: before this release such a push reached the collector and stopped it. After upgrading, check collector detail pages for an incompatible marker; it means your latest change has NOT been applied there. Remove the extension requirement or move the collector to a distribution that contains the extension, and the next push goes through.

  27. When a pushed configuration fails to start on an OpenTelemetry Collector (OpAMP), the server now rolls that collector back to its last good configuration instead of leaving it crash-looping on the new one.

    Written by us

    Before you upgrade

    Declared as breaking by product management, not by a commit footer: a failed change no longer shows up as a down collector, so anything that relied on that signal (an alert on collector restarts) will stay quiet. After upgrading, watch for collectors and destinations marked misconfigured: that means the last change was rolled back and is NOT running. Fix the cause the destination names (for example a missing TLS file) and push again. How the rollback, the per-source rates on collector cards and the route rule work: https://linkmesh.io/docs/how-to/create-a-custom-source-or-destination/

  28. Upgrading a Debian or Ubuntu package install whose /etc/linkmesh/config.yaml you have edited stops at a dpkg prompt asking whether to keep or replace that file; an unattended upgrade waits there indefinitely.

    Written by us

    Before you upgrade

    Declared by product management, not by a commit footer: this release ships new configuration defaults, so dpkg treats config.yaml as a changed configuration file. WHO IS AFFECTED. .deb installs where /etc/linkmesh/config.yaml was edited after installation. WHEN YOU UPGRADE: answer N (keep your currently installed version) when dpkg asks about /etc/linkmesh/config.yaml. For unattended or scripted upgrades pass --force-confold, for example dpkg -i --force-confold linkmesh-server_<version>.deb or apt-get -o Dpkg::Options::=--force-confold install linkmesh-server. AFTER YOU UPGRADE: the new defaults are written beside your file as /etc/linkmesh/config.yaml.dpkg-dist. Compare the two and copy over any new setting you want.

Security updates

This release includes 1 security update in shipped dependencies. Severity not stated by the advisory source.

1 of these carry no published severity, so the highest severity above does not describe them.

Which packages, and which advisories
PackageToSeverityAdvisory
github.com/klauspost/compressv1.18.7not publishedGHSA-259r-337f-4rfw

Fixes

  • S-4754 S-5076Source and destination changes on a collector group, Sync Config and Deploy to Fleet now reach every member collector; before, some members never received the configuration.
  • S-5112Deploy to Fleet offers fresh collectors for an OTLP source again, instead of claiming that every collector already has the source activated.
  • S-4753 S-4904 S-4906Collectors no longer appear offline after a server restart, an offline collector comes back as soon as it reports again, and a restart no longer writes failed logins to the Audit Log.
  • S-4896 S-4750 S-4752 S-4579Kubernetes: each node enrolled with a fleet token is its own agent, the Add Collector wizard issues a fleet token for Kubernetes, the Alloy Helm values mount /var/log, and a File Tail position survives a pod being replaced.
  • S-5078 S-4836 S-4885 S-4660 S-4529 S-4886 S-4878 S-5080 S-4872Throughput and counts are right: no more millions of records per second after a restart, rates read rec/s, each source shows its own rate on the topology card and the Inputs tab, queue capacity and drop rate are kept on both storage backends, and Active On and the Dashboard count collectors and destinations that run through a group.
  • S-4611 S-4578 S-4685Grafana Alloy collectors apply a journald source's minimum priority, run a pipeline's log parser, and no longer report every batch as failed at the last route.
  • S-4582An HTTP Check source's timeout now actually bounds the probe.
  • S-4905Behind a reverse proxy, the audit log and the login throttle record the real client address taken from your trusted proxies, and a client can no longer choose the address it is recorded under.
  • S-4875A route can no longer reference a destination that is not active where the route runs, which previously delivered nothing without saying so.
  • S-5079 S-5109The Topology layout saves on single-node (bolt) installs and survives a reload, and an expanded collector card no longer hides under its neighbour.
  • S-4832Alert rules can be created, edited and switched on and off again on installs that have the seeded anomaly rules.
  • S-4454 S-4455Single sign-on no longer reports a failure after a successful sign-in, and explains why it cannot start on an insecure origin.
  • S-4567Git settings can be read again on MongoDB installs.
  • S-4620 S-4684Typed source settings and edits in the Add Input dialog are no longer overwritten when the template list finishes loading.
  • S-4914 S-4576A plain OAuth token URL is no longer stored as a secret, and a refused credential shows its error on the secret field.
  • S-4901 S-5110 S-4908 S-4669 S-4909 S-4584 S-4903 S-4902Smaller fixes: reloading the Health page shows the app, the Health page's Recent Events line up and a collector name there opens without a page reload, activation rows show real dates instead of Never, group details use the same tab layout as collectors, the managed-by tag opens its group, a slow server reads as a timeout, and the SMTP relay is logged at startup.

Features and improvements

  • S-4438 S-4439 S-4441 S-4870Custom sources and destinations: on OpenTelemetry Collector (OpAMP) collectors you can write a component's own configuration body, including component types LinkMesh has no template for, directly from the create and edit dialogs.
  • S-4761 S-4763 S-4762 S-4887 S-4951Collector extensions: declare any OpenTelemetry Collector extension on a collector or a group, reference it from a custom body as ${ext:<label>}, and let a built-in destination authenticate through a declared authenticator extension.
  • S-4443 S-4871 S-4874 S-4883 S-4882 S-4445 S-4440A custom body or extension that would stop a collector is refused when you save it, not discovered when the collector crash-loops: unknown settings, component types the collector does not have, ports already in use and non-authenticator references are all caught at the write, and a push that needs an extension a collector lacks is withheld and the collector is marked incompatible.
  • S-4446 S-4766 S-4447LinkMesh reads each OpenTelemetry Collector's real component inventory and shows which sources, destinations and extensions it cannot run.
  • S-4444A custom source or destination now shows its own throughput on the topology canvas and in the route's live throughput, and reads "not reported" when its component emits no throughput counters, instead of borrowing the collector's total.
  • S-5077 S-4879When a pushed configuration fails to start, the server rolls the collector back to its last good configuration, and the destination that caused it stays marked misconfigured, naming the missing file.
  • S-4898 S-4897 S-4895 S-4900 S-5019Every configuration save is now its own version: Version History marks the configuration your collectors actually run, names the sources and destinations a version touched, and a rollback never discards unsaved changes and says what it does not restore.
  • S-4899A connected Git repository is now a read-only mirror of LinkMesh's history: rollbacks reach it, and Settings shows when the repository has diverged, with a way to overwrite it.
  • S-4760 S-4916Custom destinations can use durable (disk-backed) delivery, with the Durable Delivery switch available in the UI for raw-mode destinations too.
  • S-4910 S-4911The Events tab of a collector and of a group can be searched and paged back through history.
  • S-4665 S-4666 S-4667 S-4668 S-4654 S-4912The source and destination dialogs are organised into sections with a table of contents, long field help folds into an icon beside its label, and an agent opens its own detail page.
  • S-4907Dark mode is a compact light/dark switch in the top bar that starts from your system setting and remembers your choice, and the help icon is an outlined question mark in the same gray as the other icons.
  • S-4862The login page and the SSO settings say plainly when single sign-on needs an Enterprise licence.

24 further changes — build and test work, internal refactoring, and changes with no effect you could observe — were reviewed and deliberately left out.

11 other dependency updates in shipped components, with no security relevance.

2 further updates touched our build and test tooling only, which you do not run, and are not counted above.

LinkMesh Server 1.369.4

Breaking changes

Permalink

LinkMesh is in Early Access. Releases in this phase carry frequent and numerous breaking changes, so read every upgrade note below before you upgrade — a small version bump is not a routine one. This release makes the Prometheus, OTLP, syslog, file and Kubernetes sources properly configurable and secure, and lets data survive a collector restart. Settings that were silently accepted and then discarded are now honoured or refused at the write — hence 21 breaking changes.

Breaking changes

This release contains breaking changes. Read the upgrade notes below before upgrading.

  1. An unlicensed server now enrols at most 5 collectors (was 25) and refuses API automation — service-account tokens, config-as-code and Git-settings writes return 403 license_automation_required.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Only installs running with NO licence file at /etc/linkmesh/license.key. A paid licence (tier managed, standards or mixed) is unaffected in every respect: same cap, and API automation continues to work.

    WHAT CHANGES, in two independent parts.

    1. The unlicensed collector cap drops from 25 to 5. Enforcement is forward-only, so an existing unlicensed install already running 6 to 25 collectors KEEPS them and they keep delivering telemetry — LinkMesh is not in the data path. What it cannot do is enrol another one: the next enrolment is refused with 403 license_cap_reached until the fleet is back under the cap or a licence is applied.
    1. API automation now requires a paid licence. With no licence file, or with a free tier "community" envelope, these return 403 with the machine-readable code license_automation_required:
      • creating, updating or deleting a service account, and minting or rotating its tokens;
      • ANY mutating request (POST/PUT/PATCH/DELETE) authenticated with a service-account token, on any path;
      • config-as-code commit, publish, rollback and discard;
      • writes to /settings/git.

    Reads are never affected — GET stays open on every path, for every principal including a service-account token, so existing monitoring and inventory scripts keep working. The web UI is likewise unaffected: creating collectors, editing pipelines, sources, destinations and processors, and uploading a licence all continue to work on every tier. No product feature is paywalled. Agent and OpAMP enrolment are unchanged and still take the collector cap, not this gate.

    BEFORE YOU UPGRADE.

    If you run unlicensed with more than 5 collectors, or you drive this server from Terraform, Ansible, a CI pipeline, a GitOps webhook or any script using an lmsat_ token, register at https://portal.opensight.ch first. Registration issues a signed 25-collector Community licence at no cost; upload it at Settings -> License (or linkmesh-server license apply) and the cap returns to 25. Note that the free Community licence deliberately does NOT restore API automation — that requires Enterprise (https://linkmesh.io/pricing/).

    If neither applies to you, no action is needed.

    HOW TO CHECK YOUR OWN SERVER, before or after upgrading:

    linkmesh-server license info

    reports the cap and an "API automation" line, and GET /api/v1/license returns the same as maxCollectors and canAutomate. Settings -> License shows both in the UI.

    AIR-GAPPED INSTALLS. Nothing about this reaches the network: linkmesh-server still phones home to nobody, and licence verification stays a local Ed25519 signature check. Registration happens on the portal from any machine; the artifact is a .key file you carry in.

    ALSO FIXED, and it matters for the step above: on the container image, /etc/linkmesh was owned by root while the server runs as uid 1000, so PUT /api/v1/license returned HTTP 500 "License verified but apply failed" after the envelope had already verified correctly. Licence upload therefore could not succeed on any container install before 1.362.0. If you previously tried to apply a licence in a container and hit that error, the file was never written — retry the upload on this version. Kubernetes installs that mount the licence as a read-only Secret at that path were never affected.

  2. An OTLP source now listens on exactly the protocols its config names — a gRPC-template source stops opening port 4318, an HTTP-template source stops opening 4317.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Anyone whose senders reach an OTLP source on a port the source was never configured for. Before this release an OTLP source opened both 4317 (gRPC) and 4318 (HTTP) regardless of what its config said, so a sender could be pointed at the undeclared port and it worked by accident. On the next config apply after upgrading, that traffic stops being received.

    BEFORE YOU UPGRADE, in this order.

    1. List your OTLP sources and note which were created from the "OTLP gRPC" or "OTLP HTTP" template, plus the OTLP placeholder source that a freshly enrolled collector gets — that placeholder now opens gRPC only.
    1. For each one, check what your senders actually target. If anything sends to 4318 on a gRPC-template source (or 4317 on an HTTP-template source), you are relying on the old behaviour.
    1. Set BOTH endpoints on any source that must keep accepting both protocols: fill in gRPC Endpoint AND HTTP Endpoint on the source, or on that collector's activation override if only one collector needs both. Do this before upgrading, not after — the change takes effect on the next config push.
    1. Where you would rather move the senders, repoint them at the declared port instead. Either is fine; doing neither drops that telemetry silently at the sender's end.

    AFTERWARDS. Check the source's status view: a source that is listening and receiving reports data; one whose senders have gone elsewhere will show no data rather than an error, because nothing is failing — the packets simply arrive at a closed port.

  3. Create and update requests carrying a field the API does not recognise are now refused with 422 instead of silently dropping it — sources, pipelines, routes, collector groups, user groups, roles, claim mappings, processor templates, alert rules, Git settings, enrolment tokens and pipeline dry-run.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. API clients only. The web UI never sends unknown fields. If you drive LinkMesh from Terraform, Ansible, a script or a CI job, read on.

    WHAT CHANGED. An unrecognised field used to be dropped without a word and the request answered 2xx. Any client relying on that was already broken — it believed it had configured something the server never stored. The request is now refused with 422 and the error names the offending field.

    BEFORE YOU UPGRADE.

    1. Replay your automation against a staging server on this version, or diff the payloads your client sends against the API schema at /api/v1/openapi.json. A 422 naming a field is the whole diagnosis.
    1. Look first at config-shaped keys on sources and destinations. A setting that belongs inside defaultConfig but was sent at the top level is the most common case, and the error says so by name.
    1. Two specific renames are refused by name rather than ignored: configYaml on PATCH /pipelines/{id}, and kind on PATCH /collector-groups/{id}. Remove them.
    1. Note one status-code change: unknown-field refusals on destinations move from 400 to 422. A client that branches on 400 needs to accept 422 as well.

    WHAT DOES NOT CHANGE. Reads are untouched. Stored records are untouched — nothing is rejected until something writes to it.

  4. A route created through POST /api/v1/routes without an isFinal field is now final (first-match-wins), where it was previously non-final whenever the request also carried an inputFilter.

    Written by us

    Before you upgrade

    Affects API clients that create routes. Before upgrading, find any automation that creates a route with an inputFilter and no explicit isFinal, and relies on the event continuing on to lower-priority routes. Set isFinal: false explicitly on those calls. Routes already stored are not changed by this release — if you want existing non-final routes to stay non-final, nothing to do; if you want them corrected, PATCH them. Conversely, duplicate delivery that was being absorbed downstream stops at the next route you create.

  5. POST /api/v1/routes now creates a route enabled when the request omits the enabled field, so a route starts forwarding as soon as it is created.

    Written by us

    Before you upgrade

    Affects API clients that create routes ahead of time and rely on them staying inert until a separate PATCH enables them. That pattern now forwards telemetry immediately, which can mean vendor ingest cost earlier than you expected. Before upgrading, add enabled: false explicitly to those create calls — it is honoured unchanged. Routes created through the UI are unaffected, and routes already stored are untouched.

  6. GET /api/v1/entity-health now returns an object {status, lastDataAt?} per entity instead of a bare status string, and the vocabulary gains "stopped" and "unknown".

    Written by us

    Before you upgrade

    Affects external consumers of GET /api/v1/entity-health only; the bundled UI is updated. A client that reads each map value as a string will now read an object. Before upgrading, change those readers to take .status, and accept the two new values "stopped" and "unknown" alongside ok, erroring and no_data. The optional lastDataAt field is new and can be ignored.

  7. A Kubernetes collector-group member that stops reporting for longer than fleet.reapAfter (default 24h) is now removed from the group and releases its licence seat.

    Written by us

    Before you upgrade

    Affects Kubernetes collector groups only. VM collectors, VM groups, and collectors that are merely offline are untouched. A reaped node rejoins automatically when it comes back — but it re-takes the licence cap check to do so, so if your fleet is at the cap, a node returning from a long outage can be refused enrolment. Before upgrading: if you run near your collector cap, either leave headroom or raise the licence; if you would rather prune group members by hand as before, set fleet.reapAfter to a negative duration, which disables reaping entirely.

  8. Prometheus scrape limits and metric_relabel_configs that were stored but silently ignored now take effect, so an affected source can start capping scrapes or dropping metrics that were previously forwarded.

    Written by us

    Before you upgrade

    This is the one item in this release that can REDUCE the telemetry you receive without any configuration change on your side. Before upgrading, review every Prometheus source whose stored config carries any of: sample_limit, target_limit, label_limit, label_name_length_limit, label_value_length_limit, body_size_limit, metric_relabel_configs. Those settings had no effect on either runtime until now. If a value was set experimentally, or copied from elsewhere, clear the field (or set a limit to 0) to turn it off before the next config push. Sources authored as a hand-written config: document are unaffected — that path already passed through verbatim.

  9. Saving a Prometheus source whose targets entries are not plain host:port is now refused with 422 invalid_scrape_target instead of accepted.

    Written by us

    Before you upgrade

    A scheme-prefixed target such as "https://prom.corp:9090" was accepted before and then bricked the collector on apply, so this refusal replaces a silent failure. It applies to the source and to a source activation's config overrides. Before upgrading, rewrite any such target as a plain address ("prom.corp:9090") and express the rest in the dedicated fields: select https in the new Scheme field, and put any path in Metrics Path. Stored sources are not rejected until something writes to them, but a collector running one was already failing.

  10. A source config carrying a key LinkMesh cannot render on the Grafana Alloy runtime is now refused with 422 unrenderable_on_alloy instead of being stored and silently dropped — including the hand-authored Prometheus config: document.

    Written by us

    Before you upgrade

    The hand-authored config: document on a Prometheus source used to pass through to the otelcol receiver verbatim and vanish entirely on Alloy. A source carrying one can no longer be saved or activated. Everything that document was the only route to is now a typed field that renders identically on both runtimes: scheme, basic_auth, bearer_token, tls_config, proxy_url, no_proxy, proxy_from_environment, the six cardinality caps, and metric_relabel_configs. Before upgrading, find your Prometheus sources that use a raw config: block and rewrite each setting into the matching field. The 422 names the offending key and the field to use instead, so a save attempt is a usable checklist. Stored configs are not rejected until something writes to them.

  11. The Docker Stats source type is retired — it is gone from the Receiver Type list, the API refuses creating one, and the config importer no longer recognises a docker_stats receiver.

    Written by us

    Before you upgrade

    Sources already using Docker Stats keep collecting, keep their metrics pipeline and stay editable. Only creating new ones stops. No action is required to upgrade. For new container metrics, use a container-aware Host Metrics source with root_path set, or Kubernetes Node Metrics (kubeletstats). If you import collector configs, strip any docker_stats receiver from them first — the importer will no longer recognise it.

  12. A source config carrying a Kubernetes setting the collector cannot load is now refused at the API write with 422 invalid_k8s_source_config instead of stored.

    Written by us

    Before you upgrade

    Because defaultConfig is a free-form map, this can reject a record that saved before. The refused values are: an extra_metadata_labels entry other than container.id or k8s.volume.type; a k8s_api_config.auth_type outside none, serviceAccount, kubeConfig and tls; a distribution other than kubernetes or openshift; an unparseable metadata_collection_interval; an exclude_watch_type entry that is not a Kubernetes watch verb; and namespace on a k8s_cluster source. Before upgrading, check any Kubernetes source you authored through the API. Fix the value the 422 names; for namespace, move it to namespaces as a list.

  13. A TCP Log or UDP Log source config carrying a setting that receiver does not have is now refused at the write instead of being stored and silently ignored.

    Written by us

    Before you upgrade

    Only API-authored configs can hold these keys — neither template ever offered them, and they never did anything. On UDP Log the refused keys are tls, max_log_size and multiline; on TCP Log it is async. Refused on the same terms and previously storable by the same route: an encoding the collector cannot build, both multiline patterns at once, an uncompilable framing pattern, and a non-positive async counter. Before upgrading, remove those keys from any API-authored raw-log source. The next write that carries the config is refused until the key is gone.

  14. A File Tail source config carrying a key LinkMesh cannot render on both runtimes is now refused with 422 invalid_filelog_config instead of accepted.

    Written by us

    Before you upgrade

    Affects API callers only — no key in this set is reachable from the UI, and every one of them was previously written into the OpAMP config and silently dropped from the Alloy one. Refused: operators (the source's own pipeline generates the receiver's operator chain), delete_after_read, attributes, resource, fingerprint_size, force_flush_period, retry_on_failure, the raw storage argument (use the checkpoint toggle, which wires the storage extension for you), and any key that is not a File Tail field at all. The refusal names the key and says what to use instead. Existing stored configs are not rejected until something writes to them.

  15. Three operator-visible changes to journald and http_check sources: a multi-unit journald source now collects ALL units on Alloy (it silently collected only the first), unrenderable journald fields are refused, and http_check's endpoint list moves from endpoints to targets.

    Written by us

    Before you upgrade

    1. LOG VOLUME. A journald source listing more than one systemd unit previously collected only the first on the Grafana Alloy runtime and discarded the rest without a word. It now collects all of them, so such a source will receive MORE log volume after this release. Before upgrading, review your multi-unit journald sources and confirm you want every unit, and that your destination can take the extra volume.
    1. REFUSED JOURNALD FIELDS. A journald config carrying grep, files, namespace, start_at, all, merge, convert_message_bytes, root_path, journalctl_path or retry_on_failure is now refused at the API write instead of being passed through to the OpenTelemetry Collector — Alloy's loki.source.journal has no equivalent for any of them, so the source behaved differently depending on which runtime ran it. Use units, identifiers, matches, dmesg and directory instead.
    1. HTTP_CHECK RENAME. An http_check source's endpoint list moves from endpoints to targets, so that a target can carry its own headers, TLS and method. Stored sources are rewritten at startup and the generator still reads the old key, so nothing stops collecting — but an API write carrying endpoints is refused and names the new key. Update your automation. tcp_check is unaffected and keeps endpoints.
  16. A key other than endpoint inside an OTLP source's nested protocols.grpc / protocols.http block is now refused with 422 invalid_otlp_bounds instead of being accepted and dropped.

    Written by us

    Before you upgrade

    Reachable only by API or a hand-authored config — the form has never written that shape. A config using the nested block was stored with a 201 and then dropped by both config generators without a word, so it already did nothing. It is refused rather than left to be rediscovered because it is the shape upstream's own documentation shows. Before upgrading, move any such setting into the top-level grpc / http block this release adds, which is the working spelling and now carries the size limits, keepalive, CORS and custom URL paths.

  17. Destination queue settings (durable_queue, queue_storage_directory, queue_size, block_on_overflow) are now validated instead of stored and ignored, and refused with 422 invalid_durable_queue where they cannot be honoured.

    Written by us

    Before you upgrade

    A client that previously sent any of these keys believed it had configured durability and had not; the write now says so. The refusal fires when the destination type cannot carry a sending queue on both runtimes (Loki, Prometheus Remote Write, File), when a queue directory is relative, when the queue depth is not a positive number, or when a companion setting is given with durable delivery switched off. Explicitly falsy values — durable_queue: false, an empty queue_size — are treated as silence and still accepted, so ordinary edits are unaffected. Before upgrading, check any automation that sets these on a Loki, Prometheus Remote Write or File destination: those combinations will now be refused, and they never worked. Also note that a NEW destination is durable by default from this release.

  18. A Kubernetes Node Metrics (kubeletstats) source activated on a Grafana Alloy collector is no longer rendered — it emitted a component Alloy does not have, which made that collector's entire config unparseable.

    Written by us

    Before you upgrade

    This trades one loss for a larger recovery: the affected collector's other sources and destinations start working again, and its node metrics stop. Before upgrading, list any Kubernetes Node Metrics sources activated on Alloy collectors. Move them to an OpAMP/otelcol collector, which collects them unchanged. Alloy collectors that never ran a Node Metrics source are unaffected.

  19. The Kubernetes (OpAMP/otelcol) install command now also creates a ServiceAccount, ClusterRole and ClusterRoleBinding, so applying it requires permission to create cluster-scoped RBAC.

    Written by us

    Before you upgrade

    Existing deployed collectors are unaffected until they are reinstalled. Before your next Kubernetes install, check that the credentials running kubectl apply can create a ClusterRole and ClusterRoleBinding — an apply that used to succeed will fail without them. This is the cost of a real fix: the collector the old manifest produced could not run a Kubernetes source at all, because it had no permission to read the API server. If your cluster policy forbids cluster-scoped RBAC from the installing identity, have a cluster administrator apply the RBAC half once, then run the install.

  20. Kubernetes Pod Logs records now carry log.file.path and the k8s.namespace.name / k8s.pod.name / k8s.container.name / k8s.pod.uid / k8s.container.restart_count attributes, where before they carried none of them.

    Written by us

    Before you upgrade

    Nothing stops working and no configuration changes, but the delivered telemetry is not what it was. Before upgrading: review any pipeline, dashboard or alert rule written against the attribute-less records these sources used to produce — they will now see a different record shape. If a destination maps attributes to index labels, Loki in particular, it gains those labels, which changes stream cardinality and can affect your ingest cost and existing queries. Adjust queries and any relabelling before the next config push rather than after.

  21. A hostmetrics source config carrying a per-scraper setting LinkMesh does not render on both runtimes is now refused with 422 invalid_hostmetrics_config instead of being accepted.

    Written by us

    Before you upgrade

    Reachable only by API or a hand-authored config — the form never offered these, and every existing source generates byte-identical config. Such a setting reached otelcol and vanished on Alloy, so a config using one already meant two different things depending on the runtime. Refused keys: filesystem include_mount_points and include_fs_types (use the exclude filters instead), load.cpu_average, per-metric metrics.<name>.enabled, initial_delay, mute_process_user_error, mute_process_cgroup_error, exclude_devices. Before upgrading, remove them from any API-authored hostmetrics config. The scraper NAME list is unchanged, and this release also adds root_path so a containerised collector reports the host rather than itself.

Deprecations

  • The Docker Stats source type is deprecated: existing sources keep collecting and stay editable, but no new one can be created.

    Stops working in a future release, not yet fixed.

    Docker Stats never had a configuration form and is gone from the Receiver Type list; the API refuses creating a source with it, and the config importer no longer recognises a docker_stats receiver. Existing Docker Stats sources are unaffected by this release — they keep collecting, keep their metrics pipeline and remain editable. Migrate them when convenient: use a container-aware Host Metrics source with root_path set, or a Kubernetes Node Metrics (kubeletstats) source in a cluster. No end-of-life version is fixed yet; this note will be updated when one is.

Security updates

No security updates in this release.

Fixes

  • S-4506Editing a Source or a Destination now pushes the change to the collectors running it. An edit previously sat unapplied until something else triggered a config push.
  • S-4507 S-4530A new route is created enabled and final, instead of being silently inert or fanning one event through to several routes' destinations.
  • S-4423 S-4511A Prometheus source no longer emits an invalid receiver on either runtime, and the Alloy builder now renders the source config it was given or refuses the save, instead of storing keys it silently drops.
  • S-4515An OTLP source opens only the protocols its configuration names, rather than always opening both 4317 and 4318.
  • S-4605 S-4606Kubernetes sources load on Grafana Alloy again, and a Kubernetes Node Metrics source no longer makes an Alloy collector's entire configuration unparseable.
  • S-4601Kubernetes Pod Logs carry Kubernetes metadata again — namespace, pod, container, pod UID, restart count and the log file path.
  • S-4600 S-4609 S-4624The shipped Kubernetes manifest starts, includes the RBAC the Kubernetes sources need, and gives the collector a writable temporary directory so a File source can checkpoint.
  • S-4513Source status says what it actually knows — running, stopped, erroring or unknown, with the time data was last seen — instead of reporting "No data" for every uncertain case.
  • S-4592A collector that crashes reports its real reason through OpAMP health, instead of a generic failure.
  • S-4518A syslog source parses the RFC its senders actually speak.
  • S-4492 S-4494 S-4495Collector group membership stays true to the fleet: deleting a collector removes it from its group, deleting a group takes its configuration tree with it, and Kubernetes group members that are gone are reconciled away and release their licence seat.
  • S-4523Every Receiver Type the New Source dropdown offers now has a configuration form behind it; the Docker Stats type, which had none, is retired for new sources.
  • S-4386A create or update request carrying a field the API does not recognise is refused and the field named, instead of being silently discarded while the request reports success.
  • S-4128Sidebar navigation icons render as real glyphs in brand blue instead of placeholder question marks.

Features and improvements

  • S-4508 S-4509 S-4510 S-4512Prometheus scraping is now properly configurable: HTTPS with a Scheme field and a separate Metrics Path, basic auth, bearer token, a private CA, a corporate proxy, and per-scrape cardinality caps with metric filtering.
  • S-4516 S-4526An OTLP listener can be secured and bounded: TLS and mutual TLS, request size limits, keepalive, CORS, and a custom URL path.
  • S-4519 S-4522The syslog TCP and raw TCP log listeners can run behind TLS, and both raw log sources now control framing, encoding and maximum log size.
  • S-4520 S-4521 S-4610Data survives a collector restart: File Tail and Kubernetes Pod Logs resume where they left off instead of re-reading or losing what was written, destinations keep a persistent sending queue with a chosen answer to a full queue, and a new destination is durable by default.
  • S-4524Kubernetes sources can be scoped and authenticated — namespaces, API authentication mode, cluster distribution, metadata collection interval and watched resource types.
  • S-4525 S-4517Host Metrics scrapers are configurable rather than only switched on or off, including root_path so a containerised collector reports the host it runs on instead of its own container.
  • S-4527An http_check target carries its own headers, TLS settings and HTTP method, and a journald source can be scoped by unit, identifier and match.
  • S-4493A collector managed by a group shows a compact "managed by" tag, and the tabs the group owns are locked so a per-collector edit cannot silently diverge from it.
  • S-4501The unlicensed free tier is 5 collectors and no API automation. Registering at portal.opensight.ch issues a free signed Community licence that restores the 25-collector cap; API automation requires Enterprise.

21 further changes — build and test work, internal refactoring, and changes with no effect you could observe — were reviewed and deliberately left out.

8 other dependency updates in shipped components, with no security relevance.

LinkMesh Agent 1.76.2

No breaking changes

Permalink

Nothing in this release breaks an existing install: it adds a one-command support bundle, makes --strict redaction catch every IP address form, keeps a Kubernetes collector's identity across pod replacement, and ships two dependency security fixes.

Breaking changes

No breaking changes in this release.

Reviewed every change since 1.74.1. Nothing an existing install relies on was removed or renamed: no flag, config key, API or on-disk format. The changes add a command, tighten --strict redaction and fix bugs.

Security updates

This release includes 2 security updates in shipped dependencies. Severity not stated by the advisory source.

2 of these carry no published severity, so the highest severity above does not describe them.

Which packages, and which advisories
PackageToSeverityAdvisory
golang.org/x/netv0.56.0not publishedCVE-2026-46600
golang.org/x/textv0.39.0not publishedCVE-2026-56852

Fixes

  • S-3231 S-3693 S-3695--strict redaction now masks IP addresses in every form it previously missed: IPv6, IPs inside URLs and host:port, and IPs in agent log tails and config bodies.
  • S-4492On Kubernetes, a collector keeps its identity when its pod is replaced, instead of showing up as a new collector.
  • S-4314The Kubernetes agent ConfigMap template accepts a server URL that is not https.
  • S-3230The agent daemon starts its local IPC server, so local CLI commands can reach the running agent.

Features and improvements

  • S-3020New linkmesh-agent support-bundle command: one command on the host collects diagnostics into a single archive, redacted, ready to attach to a support request.

8 further changes — build and test work, internal refactoring, and changes with no effect you could observe — were reviewed and deliberately left out.

20 other dependency updates in shipped components, with no security relevance.

LinkMesh Server 1.350.4

Breaking changes

Permalink

Public promotion works again. This is the first installable release since 31 August, and it closes a collector-crashing route filter, three permission holes, and the two Critical OpenSSL CVEs that had blocked every public cut.

Breaking changes

This release contains breaking changes. Read the upgrade notes below before upgrading.

  1. GET and POST /api/v1/config/{id} and POST /api/v1/config/status are gone.

    Written by us

    Before you upgrade

    1. Search your tooling, scripts and API clients for /api/v1/config/ — those three routes no longer exist.
    2. To preview a collector's rendered config, call GET /api/v1/collectors/{id}/config/preview. That path requires collectors:read on that collector (or a superuser token).
    3. If you never called the legacy /config routes, this does not affect you.
    4. There is no compatibility shim. A caller of the old path gets 404.

Security updates

This release includes 3 security updates in shipped dependencies. Highest severity: high.

1 of these carry no published severity, so the highest severity above does not describe them.

Which packages, and which advisories
PackageToSeverityAdvisory
google.golang.org/grpcv1.83.1highCVE-2026-84304
google.golang.org/grpcv1.83.2highCVE-2026-84445
golang.org/x/cryptov0.56.0not publishedCVE-2026-78662

Fixes

  • S-4399A route filter such as attributes["env"] == "prod" no longer crashes the collector when the source also carries metrics. An unparseable filter is refused on the request instead.
  • S-3284 S-3958Clicking outside a dialog, or pressing Esc, no longer discards unsaved edits. That holds for the processor config modal and the other eight dialogs that used the same dismiss behaviour.
  • S-4306The New Source Receiver Type list includes Kubernetes and synthetic-check receivers. Picking a Kubernetes template no longer displays Syslog.
  • S-4307Switching source template replaces name and description with that template’s own values unless you typed them yourself.
  • S-4331Kubernetes collector adoption accepts a serverUrl on the request, so an in-cluster collector can be pointed at the ClusterIP instead of the public hostname.
  • S-4377Config-as-Code and Git settings require the settings permission. A viewer token can no longer publish fleet config or repoint the GitOps repo.
  • S-4378Rotating a service-account token now applies the same no-escalation checks as minting one. Holding only service_accounts:create no longer hands you a raw token with someone else’s permissions.
  • S-4279The processor-type list no longer offers resource or redaction (Alloy rejects the whole config if either is present) and includes groupbyattrs and span.
  • S-3878--strict on support-bundle no longer claims to mask hostnames. It never did; the claim was wrong and the behaviour is unchanged.
  • S-4479The shipped image no longer contains libcrypto3/libssl3 3.5.7-r0. Those two Critical CVEs were what blocked public promotion.
  • S-3753Docker Hub :latest and the public package channel track this release. They had been frozen on the 31 August build because a public tag failed CI.
  • S-3778Generate Data’s Enrol-an-agent action keys off a named error code, not the wording of the error message.
  • S-4379An authenticated caller without collectors:read can no longer fetch another collector’s rendered config. The legacy /api/v1/config/{id} path is gone; use GET /api/v1/collectors/{id}/config/preview.

Features and improvements

  • S-4138You can define a sampling policy in the server and have it delivered over the existing config push. A policy that would drop an entire signal is refused at save time.
  • S-3209PII masking reports detections per rule on the coverage view, and distinguishes “no matches” from “not instrumented”.
  • S-3561PII masking recognises Swiss UIDs (CHE-123.456.789 and the compact form).
  • S-3285The custom-processor wizard shows the placeholder syntax for each field you define, and warns if a field is defined but unused, or referenced but undefined.
  • S-1220reset-password and list-users work with the server process stopped — they open the database directly, which is the recovery path when you are locked out.

22 further changes — build and test work, internal refactoring, and changes with no effect you could observe — were reviewed and deliberately left out.

10 other dependency updates in shipped components, with no security relevance.

This release is no longer available to download.

The files for this release are gone and cannot be rebuilt, so we can no longer honestly offer it.

Upgrade to 1.350.4 or a later release; those remain available.

Withdrawn on . What it changed is kept below, so you can still read your way forward from a version you are running.

LinkMesh Server 1.342.8

Breaking changes

Permalink

Breaking changes

This release contains breaking changes. Read the upgrade notes below before upgrading.

  1. The internal certificate authority and every client-certificate endpoint, config key and permission is gone. Collectors authenticate with a Bearer token over TLS, and nothing else.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. You are affected if any of these is true: you set a ca: block or the CA_SERVER_SECRET environment variable in your server configuration; you have scripts or monitoring that call /api/v1/certificates/... or /api/v1/ca/...; or you built a custom role that grants any certificates:* permission. If none of those applies, this changes nothing for you and your collectors keep connecting exactly as before.

    WHAT CHANGED, precisely.

    • The whole ca: configuration block is removed: ca.serverSecret (and its CA_SERVER_SECRET environment binding), ca.keySize, ca.validityYears, and ca.subject.CN / .O / .OU. They are no longer read. Leaving them in your config file is harmless but does nothing.
    • These HTTP endpoints no longer exist and now answer 404: everything under /api/v1/ca/, everything under /api/v1/certificates/ including GET /api/v1/certificates/chain.pem, the certificate listing, and POST /api/v1/certificates/renew.
    • The Certificates section is gone from the web interface.
    • The certificates:read, certificates:update and related permissions are removed from the built-in roles, and a one-shot migration at first boot strips them from any custom role that still carries them.

    UPGRADE STEPS.

    1. Before upgrading, search your server configuration for a ca: block and for CA_SERVER_SECRET in your environment, systemd unit or Kubernetes manifest. Delete them. This is tidy-up, not a prerequisite — an unread key breaks nothing — but leaving them in place will mislead whoever reads that file next.
    2. Search your own tooling for the string /certificates and /ca/. Anything calling those paths must be removed; there is no replacement endpoint, because there is no longer anything to issue, list or renew.
    3. Upgrade and let the server start once. The role migration runs at boot and needs no input.
    4. After the first boot, open Access Control and check any custom roles you maintain. A role whose only purpose was certificate administration will now grant nothing; delete it or repurpose it deliberately rather than leaving an empty role in the list.

    WHAT HAPPENS IF YOU SKIP THIS. Nothing breaks at upgrade time, and no collector drops off — this is the important part, because the change sounds far more alarming than it is. Your collectors already authenticate with the durable Bearer token and continue to do so untouched. What fails is tooling: a monitoring check or script that polls a certificate endpoint starts returning 404, and depending on how it is written it will either alert or fail silently. That is the failure to look for, and it will not announce itself as being related to this upgrade.

    WHY THIS CHANGED, because the removal of a security mechanism deserves an explanation. Server-pushed client certificates were built to the OpAMP specification's model — bootstrap with a token, receive a certificate over the live session, reconnect with mTLS. Lab testing established that the canonical opampsupervisor (v0.23.0) does not advertise support for receiving connection settings, silently ignores a certificate offer, and worse, stalls its own status and heartbeat loop within about six seconds of receiving one: the collector drops offline while systemd still reports it connected. This was reproduced four times, across first enrolment, re-enrolment and rotation. So the machinery was not a working security feature being withdrawn; it was a feature that could take a healthy collector offline, and it is removed for that reason. The durable Bearer token over TLS terminated at the ingress is the steady-state credential for both Alloy and OpAMP collectors, which is how OpAMP fleets are run in practice.

    The trade-off, stated plainly: there is no per-collector, individually revocable transport credential. Revocation is by enrollment token or by deregistering the collector, not by certificate serial. If you need genuine mTLS, it must be provisioned out of band at install time (cert_file / key_file in supervisor.yaml); the server-side reader for that path is kept and inert, so a collector that presents a client certificate at connect time still authenticates end to end. That path is not built and not supported.

    Shipped in v1.267.1, 2026-07-10.

  2. Enrollment tokens are shown once, at creation. The token list no longer returns the token itself, and the plaintext of every existing token is erased from the database at first boot.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Anyone who reads an enrollment token back out of the interface or the API when enrolling a new collector — rather than keeping it from the moment it was created. If your enrolment runbook says "go to Settings, copy the token, paste it into the install command", that runbook stops working. Your already-enrolled collectors are not affected and do not need to be touched.

    WHAT CHANGED. Enrollment tokens were stored in plaintext and returned in full on every list call. They are now stored as a SHA-256 hash, exactly as API tokens and OTLP tokens already were. The raw value is returned once, in the response to the call that creates it, and never again. The list shows only the first eight characters as a non-secret handle, plus the metadata.

    A one-shot migration runs at first boot: it computes the hash for every existing token and erases the stored plaintext.

    UPGRADE STEPS.

    1. Before upgrading, decide whether you need any of your current enrollment tokens in readable form. If you do — for example it is pasted into a configuration-management template, a runbook, or a password manager entry you have not filled in yet — copy it now. After the upgrade it cannot be recovered from the server by any means, including from the database directly.
    2. Upgrade and let the server start once. The migration is automatic, idempotent, and needs no input.
    3. Verify the fleet is still connected. Every collector holding a raw token continues to authenticate, because the token it presents hashes to the value the migration backfilled. This was the specific risk in this change and it is explicitly covered by tests, but it is worth confirming in your own environment: the collector list should show the same number of connected collectors as before the upgrade.
    4. Update any runbook or template that says to copy a token out of the token list. The new shape is: mint a token, copy it immediately from the creation response, store it wherever you keep secrets.

    WHAT HAPPENS IF YOU SKIP THIS. Nothing fails during the upgrade, and no collector is disconnected. The failure arrives later and looks like a documentation problem rather than an upgrade consequence: somebody follows the enrolment runbook, opens the token list to copy the token, and finds only a short prefix. The fix at that point is simply to mint a new token — no existing collector is harmed by doing so — but the person hitting it will not know that, and will be doing it in the middle of a task that has just stopped working.

    WHY THIS CHANGED. The enrollment token is the only credential a collector presents on every reconnect. Storing it in plaintext and echoing it on every list meant that read access to the token list, or to a database backup, was equivalent to the ability to enrol a collector into your fleet.

    Shipped in v1.305.0, 2026-07-21.

  3. Plaintext credentials sitting in your committed GitOps configuration are rewritten to placeholders at first boot. Anything the server cannot recover from the live entity is skipped and needs your attention, and the old values remain in git history regardless.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Anyone whose destination or source configuration contains an inline credential — a password, an API key, a bearer token typed directly into a field rather than entered as a ${secret:name} reference. If every credential you use is already a secret reference, this changes nothing.

    WHAT CHANGED. The GitOps working clone used to hold live credentials in plaintext at its tip, because a destination's activation snapshot was committed with whatever value was in the field. A one-shot migration at first boot rewrites those committed snapshots so the credential reads as a masked placeholder instead.

    Delivery is safe by construction: the value that is actually sent to a collector is sourced from the live entity in the database, not from the committed snapshot, and a masked snapshot value is treated as "unchanged" during the merge. So masking the snapshot does not change what your pipelines deliver.

    There is one case the migration deliberately refuses to touch, and it is the one that needs you: an activation whose credential exists ONLY in the snapshot, with no live entity behind it to recover the value from. Masking that would silently break delivery, so it is skipped and a warning is logged instead.

    UPGRADE STEPS.

    1. Upgrade and let the server start once. The migration is idempotent and best-effort; a failure on one activation is logged and never stops the boot.
    2. Read the server log from that first boot and search for the migration's warnings. Each one names an activation it skipped because the credential was not recoverable from a live entity.
    3. For every skipped activation, do one of two things: convert the credential to a ${secret:name} reference using the Secrets section, or rotate the credential at the destination and enter the new value. Either resolves it. Leaving it is also a decision — the plaintext simply stays in the working clone, which is where it was before this release.
    4. Now consider rotation for everything else. This is the step people skip and it is the one that matters. The migration masks the TIP of the git history. It does not and cannot rewrite history: every credential that was ever committed is still readable in an earlier commit of that repository. If your GitOps repository is remote, shared, or backed up, treat those credentials as exposed and rotate them. If you skip this, the honest description of your state after the upgrade is "the tip is clean and the history is not".

    WHAT HAPPENS IF YOU SKIP THIS. The upgrade completes and your pipelines keep delivering. What you miss is the two things the migration cannot do for you: the skipped activations sit in the log unaddressed, and the credentials in git history stay readable. Neither produces an error, an alert or a visible symptom — which is precisely why this note exists.

    Shipped in v1.309.0, 2026-07-22, as part of the secrets work that also introduced the Secrets section, secret references and rotation.

  4. A collector group now holds one kind of collector. Adding a VM collector to a Kubernetes group, or the reverse, is refused with 422.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Anyone whose collector groups mix VM or host collectors with Kubernetes collectors, and anyone whose automation adds collectors to groups. If you run only VM collectors, or only Kubernetes collectors, this does not affect you.

    WHAT CHANGED. A collector's kind is derived from whether it enrolled through a reusable fleet token: a collector that carries a fleet id is kubernetes, everything else is vm. Both membership-mutation paths now check that kind against the group's and refuse a mismatch:

    • POST /api/v1/collector-groups/{id}/collectors returns 422 with a message naming both kinds.
    • A PATCH that sets collectorIds is checked the same way.

    Fleet-token auto-join is unaffected, because a fleet collector joins its own fleet's Kubernetes group and is consistent by construction. Adoption and discovery do not attach collectors to groups, so they are unaffected too.

    This guards the mutation paths only. An existing mixed group is not torn apart by the upgrade and keeps working.

    UPGRADE STEPS.

    1. Before upgrading, list your collector groups and check whether any holds both kinds. A group with a mix will keep functioning, but you will not be able to change its membership afterwards without splitting it.
    2. Split any mixed group into a VM group and a Kubernetes group, and attach the routes and configuration each kind needs. Do this before the upgrade if you can, because afterwards the only way to move a collector out of a mixed group is to remove it and add it to a new one — which the guard permits, but which takes more steps than planning the split.
    3. Check any automation that adds collectors to groups and make sure it handles a 422. A script that assumes a 2xx will now fail, and the message tells you exactly which kind it tried to add to which.

    WHAT HAPPENS IF YOU SKIP THIS. Nothing at upgrade time. Your mixed group keeps running with the configuration it already has. The failure arrives the next time somebody tries to add a collector to it — probably during an unrelated task, probably from a script, and the 422 will read as a permissions or validation problem rather than as a rule that was introduced here.

    WHY THIS CHANGED. A group's whole purpose is that its members share one configuration. A VM collector and a Kubernetes DaemonSet collector have genuinely different receiver topologies — different sources, different discovery, different semantics — so a config that suits one cannot suit the other. A mixed group therefore could not produce a correct configuration for all its members; the mismatch simply surfaced later, as a failed apply at the edge rather than as a refusal at the point where somebody made the mistake.

    Shipped in v1.324.0, 2026-07-23.

  5. The PII and credit-card masking templates changed their underlying processor type, and any blocked_values or allow_all_keys settings you had overridden on a masking processor are dropped rather than translated.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Anyone using a processor created from the pii-redaction or cc-masking template, and in particular anyone who edited such a processor's configuration to add or change blocked_values or allow_all_keys. If you use those templates with their default configuration, the migration handles it and you have nothing to do.

    WHAT CHANGED. Both templates were built on the redaction processor type, configured with allow_all_keys and blocked_values. They are now expressed as a transform processor with OTTL statements. The template definitions re-seed themselves at boot, so the templates migrate without help.

    What does not migrate itself is your own stored per-processor override. Configuration generation merges your override map on top of the template's default, so a leftover blocked_values / allow_all_keys pair would be rendered inside a transform block, where those keys mean nothing. Those stale keys are therefore dropped, not translated.

    The decision not to translate them was deliberate: the two shapes are not equivalent. The redaction processor took a list of value patterns; transform takes OTTL statements. A mechanical translation would have produced something that looked like your configuration and masked different things — which is worse than dropping it, because you would not know to check.

    UPGRADE STEPS.

    1. Before upgrading, list the processors in your pipelines that were created from pii-redaction or cc-masking, and for each one record whether you customised its configuration. The values you need to note are blocked_values and allow_all_keys.
    2. Upgrade and let the server start once.
    3. For each processor you noted in step 1, open it and re-express your customisation as OTTL statements in the transform configuration. The template's own statements show the form to follow.
    4. Use processor preview on a representative record to confirm the values you intended to mask are still masked. This is the only check that actually tells you whether step 3 worked.

    WHAT HAPPENS IF YOU SKIP THIS. Your pipeline deploys, the collector reports healthy, and the customisation you had added is simply not applied. Values you believed were being masked pass through unmasked. There is no error and no warning at any point, which is why step 4 is worth the few minutes.

    WHY THIS CHANGED, and why it was urgent rather than cosmetic. The redaction processor type compiles to otelcol.processor.redaction, a component that no released version of Grafana Alloy contains — it is absent at 1.0.0, 1.6.0 and 1.18.0 alike, while every other processor in the catalogue is present. Alloy parses a served remote configuration as a whole and rejects the entire thing if it names a component the build does not have. So a single unknown component cost the collector every source, every processor and every destination it had, while it continued to report itself healthy. Re-expressing the templates on transform removed a component that could silently empty a whole pipeline.

    Shipped in v1.328.1, 2026-08-02.

  6. Creating or updating a destination with configuration fields at the top level of the request is now rejected with 400. It used to return 201 and silently discard them.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Anyone who creates or updates destinations through the API with their own client or script. The web interface has always built the request correctly and is unaffected.

    WHAT CHANGED. POST /api/v1/destinations and PATCH /api/v1/destinations/{id} used to ignore any field they did not recognise. A request that put endpoint, compression, tls and so on at the top level — instead of inside defaultConfig — returned 201 Created with every one of those fields thrown away. The destination was created with no configuration at all.

    Now:

    • Unknown top-level fields are rejected with 400, and the message names each offending field individually. Where the field is recognisably a configuration field, the message also tells you that defaultConfig is where it belongs.
    • The set of known fields is derived by reflection over the model's JSON tags, so a field added later does not get rejected because somebody forgot to update a hand-written list.
    • templateId is now genuinely applied rather than ignored. An explicit value beats the template's value. An unknown templateId is a 400, not a silent no-op.

    UPGRADE STEPS.

    1. Before upgrading, find every place your tooling creates or updates a destination and check the request shape. Configuration fields belong inside defaultConfig; anything else at the top level will now be refused.
    2. While you are there, read back the destinations those scripts created. This is the important step. A destination created through the broken path has an empty configuration, which means it has been running on the schema defaults — for OTLP that is localhost:4317, and for OTLP/HTTP http://localhost:4318. In other words it has been shipping telemetry to the collector's own host rather than to the endpoint you specified. Check the defaultConfig of each one and repair anything that is empty or wrong.
    3. Upgrade, then re-run your tooling and confirm it succeeds. A 400 at this point is telling you exactly which field is in the wrong place.

    WHAT HAPPENS IF YOU SKIP THIS. Your scripts start failing with 400 at the next run. That is the intended outcome and it is the smaller half of the problem. The larger half is step 2: any destination already created through the old path is misconfigured right now, silently, and upgrading does not repair it. Nothing in the interface or the API flags it — a GET on such a destination simply reads as "not configured yet", and the collector reports healthy while delivering nowhere.

    WHY THIS CHANGED. Strict decoding was chosen deliberately over the gentler alternatives — echoing the ignored fields back, or accepting them quietly — because the previous behaviour was an operation that reported success for work it had not done. Breaking a client that is already failing silently, loudly and at the point of the mistake, is the lesser harm.

    Shipped in v1.339.3, 2026-08-19.

  7. Grafana Alloy below 1.13.0 is no longer a supported collector version. Every Alloy collector under it is flagged Unvalidated, and the recommended version moves from 1.6.0 to 1.13.2.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Anyone running Grafana Alloy collectors below 1.13.0. Check before upgrading: the collector list shows each Alloy collector's version. OpenTelemetry Collector (otelcol) collectors are unaffected — this is an Alloy floor only.

    WHAT CHANGED. Three things, and they arrive together:

    • The supported minimum for Alloy moves from 1.0 to 1.13.0. Any Alloy collector below it now carries the red Unvalidated badge where it showed nothing before. This is a fleet-wide visible change on the day you upgrade.
    • The recommended version moves from 1.6.0 to 1.13.2, so every Alloy collector below 1.13.2 now shows the amber Update badge.
    • POST /api/v1/collectors/{id}/upgrade defaults its target to the recommended version. A collector sitting on 1.6.0 used to get "already at recommended" (409) and now gets a real upgrade dispatched to 1.13.2. If you call that endpoint from a script, its behaviour has changed under you.

    The floor constrains what the server may emit into a collector's configuration. Nothing at runtime refuses to serve a configuration to a below-floor collector, so this upgrade does not cut anyone off.

    UPGRADE STEPS.

    1. Before upgrading, list your Alloy collectors and their versions. Anything below 1.13.0 is what this note is about.
    2. Upgrade those collectors to 1.13.2 — the newest patch of the floor's minor — before or soon after upgrading the server. Do them in whatever order suits you; there is no ordering constraint between server and collector here.
    3. Upgrade the server.
    4. Check the collector list. Any remaining red Unvalidated badge is an Alloy collector still below 1.13.0 and is your remaining work. An amber Update badge means merely behind the recommended version, which is a softer signal and not urgent.
    5. If you script against the upgrade endpoint, re-read what it now does for a collector on an old version: it dispatches rather than refusing.

    WHAT HAPPENS IF YOU SKIP THIS. Nothing breaks on the day. Your below-floor collectors keep receiving configurations and keep shipping telemetry, and the only immediate change is the badge.

    The risk is later, and it is severe enough to be worth stating precisely. Alloy parses a served remote configuration as a whole. If it receives a configuration naming a component its build does not contain, it does not skip that component — it rejects the entire configuration and runs nothing: no source, no processor, no destination. On a first enrolment there is no cached configuration to fall back on. And the collector continues to report itself healthy to the server throughout.

    So the day the server emits any component newer than your collector's build, that collector silently stops shipping telemetry while looking fine. That is the failure the floor exists to prevent, and being below the floor is what makes you eligible for it. If an Alloy collector stops shipping after a configuration push, check its version before anything else.

    WHY 1.13.0. It is the release that added otelcol.connector.count, which per-rule masking metrics need. Established two independent ways: the upstream changelog entry under the 1.13.0 heading (released 2026-02-05), and the component reference returning 200 at tag v1.13.0 and 404 at v1.12.2, with a control component that returns 200 at both to prove the 404 was a genuine absence rather than a documentation reshuffle.

    Shipped across v1.339.x–v1.340.1, 2026-08-21.

    ONE KNOWN GAP, recorded rather than smoothed over: the Unvalidated badge's tooltip does not name the floor version — it points at the recommended version instead, because that is the number the API sends. So the badge tells you that you are below the floor without telling you what the floor is. It is 1.13.0, and that is why it is written here.

  8. The cc-masking and pii-redaction processor templates have been removed. A migration re-anchors every affected processor at boot.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Anyone whose pipelines contain a processor created from cc-masking or pii-redaction, including disabled ones. If none of your pipelines uses either, this does not affect you.

    WHAT CHANGED. Both templates are gone from the processor catalogue, which drops from 29 to 27 entries. Masking is now built from the rule-based PII masking processor, which references maintained detector versions instead of storing a copy of a pattern.

    UPGRADE STEPS.

    1. Upgrade the server and let it start once. A migration runs at boot and re-anchors every affected processor — you do not have to edit pipelines by hand.
    2. A processor that ran the template's built-in patterns becomes a PII masking processor with equivalent detector rules. It masks the same values it masked before.
    3. A processor whose log_statements you had overridden becomes a Custom transform, with your statements preserved byte-for-byte. Nothing you wrote is rewritten.
    4. Open Pipelines and confirm each previously-affected processor now shows as PII masking or Custom transform.
    5. If one instead shows an empty Transform, it did not migrate. Do not deploy that pipeline — see below.

    WHAT HAPPENS IF YOU SKIP THIS. A processor left pointing at a removed template renders as an empty transform. The configuration is valid, the pipeline deploys, the collector reports healthy — and the data passes through unmasked. This failure is silent, which is why step 4 is worth the two minutes.

    Disabled processors migrate too, so re-enabling one later is safe.

    Shipped in v1.341.1, 2026-08-26. Note the relationship to the earlier masking change in this same release window: that one moved the templates onto a new processor type, this one removes them altogether. If you are upgrading across both — which you are, since both are inside this release — you only need to do the work described here.

  9. Stopped collectors now keep their licensed seat, and bringing a decommissioned collector back is refused at your limit. Your licensed collector count can go up after this upgrade.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Anyone at or near their licensed collector limit. If your fleet has headroom, you will see a number change and nothing else.

    WHAT CHANGED. Two things, and together they can make your licensed collector count go up after this upgrade:

    • A collector that reports it is shutting down keeps its seat. Previously a stopping Alloy collector silently freed one, while a stopping OpAMP collector did not — the same action, two different outcomes, depending on which agent you ran.
    • Bringing a decommissioned collector back into service — Reset Connection in the interface, or a re-registration — now passes the same licence check as a new enrolment. At your limit it is refused with 403 license_cap_reached.

    This is a change to what counts against your licence, so read it as a licensing change rather than as a bug fix, even though it arrived in a release that carried a great many bug fixes.

    UPGRADE STEPS.

    1. Before upgrading, record your current count: GET /api/v1/license reports maxCollectors and currentCount.
    2. Upgrade, then read the same endpoint again. A higher currentCount is expected if you run Alloy collectors that were stopped — those seats were being released silently and are now held.
    3. If the new count is at or above maxCollectors, decommission what you no longer need with DELETE /api/v1/collectors/{id}. That still frees a seat; only un-decommissioning is now gated.
    4. Collectors that were already deregistered before this upgrade are treated as decommissioned, because the reason was not recorded before now. If you intended to bring one back, do it while you have headroom.

    WHAT HAPPENS IF YOU SKIP THIS. Nothing breaks at upgrade time. The failure arrives later and looks unrelated: someone presses Reset Connection on a collector and gets a refusal, or a collector that was deliberately stopped does not come back. Both are correct behaviour, and both are surprising if the count moved and nobody looked.

    WHY THIS CHANGED. The count could previously be reset in a loop through documented endpoints — deregister to drop the count, enrol again, then reset the originals. Verified in a lab: ten collectors live under a limit of five.

    Shipped in v1.342.8, 2026-08-31 — the release itself.

Security updates

No security updates in this release.

Fixes

107 fixes in this release have not been written up yet. They are not listed here because a description written for the people who built it is no use to somebody deciding whether to upgrade.

Features and improvements

23 changes in this release have not been written up yet. They are not listed here because a description written for the people who built it is no use to somebody deciding whether to upgrade.

This release is no longer available to download.

The files for this release are gone and cannot be rebuilt, so we can no longer honestly offer it.

Upgrade to 1.76.2 or a later release; those remain available.

Withdrawn on . What it changed is kept below, so you can still read your way forward from a version you are running.

LinkMesh Agent 1.74.1

Breaking changes

Permalink

Breaking changes

This release contains breaking changes. Read the upgrade notes below before upgrading.

  1. The agent refuses to download a self-update binary over plain HTTP. Only HTTPS is accepted, plus loopback HTTP for local test harnesses.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. You are affected only if your LinkMesh server hands the agent a self-update download URL that is not HTTPS — which in practice means an on-premises or air-gapped installation serving agent binaries from an internal host over plain HTTP. If your server is reached over HTTPS, as a hosted or ingress-terminated installation is, this changes nothing.

    WHAT CHANGED. The self-update binary download URL arrives over the OpAMP control channel. The agent now validates the scheme before downloading and refuses anything that is not HTTPS. Loopback HTTP remains allowed, so local test harnesses are unaffected.

    UPGRADE STEPS.

    1. Before upgrading, check the scheme of the URL your server hands out for agent binaries. If it is http:// and not a loopback address, self-update will stop working after this upgrade.
    2. Put the binaries behind HTTPS. A certificate from an internal certificate authority is fine; the check is on the scheme, not on who signed the certificate.
    3. Upgrade the agents, then trigger one self-update and confirm it completes. This is the only way to know the path still works end to end.

    WHAT HAPPENS IF YOU SKIP THIS. Self-update stops. Nothing else does: the agent keeps running, keeps reporting, and keeps managing its collector. The failure is quiet and it compounds — agents simply stay on the version they are on, and you find out when you notice the fleet has not moved.

    WHY THIS CHANGED. Defence in depth. It is rated low severity because exploiting it requires compromising the OpAMP control channel first — but if that happens, the difference between HTTPS and cleartext is the difference between an attacker who has to compromise your server and one who only has to sit on the network path while a binary is fetched and executed as root.

    Shipped in v1.59.0, 2026-06-25.

  2. The agent refuses to upgrade a supervised OpenTelemetry Collector. upgrade returns a refusal for one, and upgrade_all silently skips every supervised collector in the batch.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Anyone running OpenTelemetry Collector (otelcol / otelcol-contrib) collectors under opampsupervisor in managed mode, and using the agent's upgrade commands on them. Managed Alloy collectors on remotecfg, and genuinely unmanaged runtimes, stay eligible and are unaffected.

    WHAT CHANGED. The agent's upgrade and upgrade_all handlers now check whether the target is a supervised otelcol before swapping its binary.

    • upgrade on a supervised otelcol is refused.
    • upgrade_all filters supervised collectors out of the batch, and refuses outright if that leaves nothing to do.

    Supervised otelcol upgrades go from the server to the supervisor over OpAMP packages instead. That path is the supported one and is unchanged by this.

    UPGRADE STEPS.

    1. Before upgrading, check whether anything you run calls the agent's upgrade commands against otelcol collectors. If you only ever upgrade Alloy collectors, you have nothing to do.
    2. After upgrading, be aware that upgrade_all now reports a smaller number than you may expect. This is the part to watch. The supervised collectors are filtered out rather than reported individually, so a batch that used to say it upgraded twelve collectors may now say it upgraded four, with no line naming the eight it skipped. If you track fleet versions, reconcile against the collector list rather than against what the batch reported.
    3. Upgrade supervised otelcol collectors through the server instead, which dispatches over OpAMP to the supervisor.

    WHAT HAPPENS IF YOU SKIP THIS. Two different things, depending on which command you use. A single upgrade fails loudly and tells you. upgrade_all succeeds quietly and does less than it used to, which is the one that will catch you out: your supervised collectors simply stay on their old version while the command reports success.

    WHY THIS CHANGED. This closed a latent crashloop. The equivalent ownership check already existed on the restart command but was missing from the upgrade handlers, so the agent could swap an OpAMP-supervised otelcol binary out from under its own supervisor. The result is worse than a version skew — and a version skew already crashloops.

    Shipped in v1.71.x, 2026-07-12.

  3. The published Kubernetes DaemonSet manifest changed its image tag from :latest to :edge, so applying it unchanged puts your agents on the internal build channel rather than the promoted release.

    Written by us

    Before you upgrade

    WHO IS AFFECTED. Anyone who deploys the agent on Kubernetes using the DaemonSet manifest we publish at packaging/k8s/linkmesh-agent-daemonset.yaml, rather than a manifest of their own with a pinned image tag.

    WHAT CHANGED. The manifest's image tag moved from :latest to :edge.

    READ THE NEXT PARAGRAPH BEFORE ACTING ON THIS ONE. The change was correct when it was made and is questionable now. In July 2026 :latest was frozen on a build from 2026-06-23 — the public promotion mechanism had never successfully run — so a manifest tracking :latest deployed a stale agent, and :edge was the only tag that moved. That freeze has since been fixed and :latest now tracks the promoted release. So the manifest as published today points Kubernetes deployments at the newest internal build rather than at the release we stand behind.

    UPGRADE STEPS.

    1. If you apply our manifest unchanged, decide which channel you actually want. For a production cluster that is almost certainly the promoted release, not the internal build stream.
    2. Pin the image explicitly. Replace the tag with the exact version you intend to run — for the agent that is 1.74.1 — rather than either floating tag. A DaemonSet that follows a floating tag will roll your whole fleet onto a new build the next time a pod restarts, at a time you did not choose.
    3. If you prefer a floating tag, use :latest, which now means the promoted release, and be aware that it moves when a promotion happens.

    WHAT HAPPENS IF YOU SKIP THIS. Your Kubernetes agents track internal builds. Those builds are tested and are not junk, but they have not been through a promotion, they have no changelog entry, and nobody has assessed them for breaking changes. You will be running versions this changelog says nothing about.

    Which tag the published manifest should carry is under review. Until that is settled, pin the version yourself rather than relying on either floating tag.

    Shipped in v1.74.x, 2026-07-23.

Security updates

No security updates in this release.

Fixes

  • S-3099The shipped Kubernetes DaemonSet manifest no longer installs a stale agent image that could not report Kubernetes inventory, which had left Kubernetes onboarding empty.

Features and improvements

  • S-2952The agent reports the ports listening on its host, so onboarding can offer them for one-click observation as a TCP Port Check source.

Latest entry: LinkMesh Server 1.399.3, released 3 October 2026. This page was built from release data generated .

Ready to move? The upgrade guide covers the order to upgrade server, collectors and agents, and how rollback works.