Log shows VersionProbe error messages after version 7.1 update

1. Describe your incident:

A few months ago I made a fresh deployment of Graylog Open 6.3 with Docker Compose while following the relevant documentation. I configured the internal Graylog CA and provisioned the Data Node certificate using the preflight interface, then used my own CA to secure the web interface, and even managed to restore old configs and several hundred GBs of data from an earlier deployment. Everything went smoothly.

So a few days ago I upgraded to version 7.0, then to 7.1, by doing docker compose down → updating the image tags in .envdocker compose up. All seemed well after the 7.0 update. But when version 7.1 went up, I saw this in the Graylog container logs (see PDF for full context):

graylog_server_logs_after_v7.1.pdf (58.1 KB)

2026-07-06 17:14:14,176 ERROR: org.graylog2.storage.versionprobe.VersionProbe - Unable to retrieve version from indexer node: Hostname 172.18.0.4 not verified:
certificate: sha256/qiZf/I2AUsNZo0ORP/iFfOA6WfC+WfCplyHr6XdyMtc=
DN: CN=datanode
subjectAltNames: [127.0.0.1, 0:0:0:0:0:0:0:1, 172.18.0.2, localhost, datanode]. - Hostname 172.18.0.4 not verified:
certificate: sha256/qiZf/I2AUsNZo0ORP/iFfOA6WfC+WfCplyHr6XdyMtc=
DN: CN=datanode
subjectAltNames: [127.0.0.1, 0:0:0:0:0:0:0:1, 172.18.0.2, localhost, datanode].
2026-07-06 17:14:14,178 INFO : org.graylog2.storage.versionprobe.VersionProbe - Indexer is not available. Retry #1/1
2026-07-06 17:14:14,178 ERROR: org.graylog2.storage.versionprobe.VersionProbe - Unable to retrieve version from indexer node:
com.github.rholder.retry.RetryException: Retrying failed to complete successfully after 1 attempts.
at com.github.rholder.retry.Retryer.call(Retryer.java:174)
at org.graylog2.storage.versionprobe.VersionProbeImpl.probe(VersionProbeImpl.java:116)
at org.graylog2.periodical.SearchVersionCheckPeriodical.doRun(SearchVersionCheckPeriodical.java:113)
at org.graylog2.plugin.periodical.Periodical.run(Periodical.java:99)
at com.codahale.metrics.InstrumentedScheduledExecutorService$InstrumentedPeriodicRunnable.run(InstrumentedScheduledExecutorService.java:264)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.base/java.util.concurrent.FutureTask.runAndReset(Unknown Source)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)

And then the three VersionProbe messages started repeating every 30s. This is flooding the logs, but I can’t find any issues with the services. Data Node logs show no errors. Inputs, searches, index maintenance etc are all working as expected. Also: curl -k https[://]datanode[:]9200 works from inside the Graylog container, so I guess it can resolve the datanode hostname without issue.

2. Describe your environment:

  • OS Information: Docker Compose on AlmaLinux 9

  • Package Version: 7.1 for Graylog and Data Node, 7.0.29 for MongoDB

  • Service logs, configurations, and environment variables:

.env

GRAYLOG_IMAGE="graylog/graylog:7.1"
DATANODE_IMAGE="graylog/graylog-datanode:7.1"
MONGODB_IMAGE="mongo:7.0.29"

docker-compose.yml

services:
  mongodb:
    image: "${MONGODB_IMAGE:-mongo:7.0.29}"
    restart: always
    networks:
      - graylog
    volumes:
      - "mongodb_data:/data/db"
      - "mongodb_config:/data/configdb"  
    environment:
      - TZ=[my-time-zone]

  datanode:
    image: "${DATANODE_IMAGE:-graylog/graylog-datanode:6.3}"
    hostname: "datanode"
    environment:
      GRAYLOG_DATANODE_NODE_ID_FILE: "/var/lib/graylog-datanode/node-id"
      GRAYLOG_DATANODE_PASSWORD_SECRET: "${GRAYLOG_PASSWORD_SECRET}"
      GRAYLOG_DATANODE_MONGODB_URI: "mongodb://mongodb:27017/graylog"
      GRAYLOG_DATANODE_OPENSEARCH_HEAP: "16g"
      GRAYLOG_DATANODE_OPENSEARCH_CONFIGURATION_OVERRIDES_FILE: "/var/lib/graylog-datanode/overrideconfig.conf"
      TZ: "[my-time-zone]"
    ulimits:
      memlock:
        hard: -1
        soft: -1
      nofile:
        soft: 65536
        hard: 65536
    ports:
      - "127.0.0.1:8999:8999/tcp"
      - "127.0.0.1:9200:9200/tcp"
    networks:
      - graylog
    volumes:
      - "datanode_data:/var/lib/graylog-datanode"
    restart: always

  graylog:
    hostname: "server"
    image: "${GRAYLOG_IMAGE:-graylog/graylog:6.3}"
    depends_on:
      mongodb:
        condition: "service_started"
      datanode:
        condition: "service_started"
    entrypoint: "/usr/bin/tini --  /docker-entrypoint.sh"
    environment:
      GRAYLOG_NODE_ID_FILE: "/usr/share/graylog/data/data/node-id"
      GRAYLOG_PASSWORD_SECRET: "${GRAYLOG_PASSWORD_SECRET}"
      GRAYLOG_ROOT_PASSWORD_SHA2: "${GRAYLOG_ROOT_PASSWORD_SHA2}"
      GRAYLOG_HTTP_BIND_ADDRESS: "0.0.0.0:9000"
      GRAYLOG_HTTP_EXTERNAL_URI: "https://my.graylog.url:9000/"
      GRAYLOG_HTTP_PUBLISH_URI: "https://my.graylog.url:9000/"
      GRAYLOG_MONGODB_URI: "mongodb://mongodb:27017/graylog"
      GRAYLOG_ROOT_TIMEZONE: "[my-time-zone]"
      TZ: "[my-time-zone]"
      GRAYLOG_HTTP_ENABLE_TLS: true
      GRAYLOG_HTTP_TLS_CERT_FILE: "/usr/share/graylog/tls/graylog.pem"
      GRAYLOG_HTTP_TLS_KEY_FILE: "/usr/share/graylog/tls/graylog.key"
      GRAYLOG_SERVER_JAVA_OPTS: "-Xms8g -Xmx8g -Djavax.net.ssl.trustStore=/usr/share/graylog/tls/graylog.jks"

    ports:
    - "9000:9000/tcp"   # Server API
    - "...[my-input-ports]..." 

    networks:
      - graylog
    volumes:
      - "graylog_data:/usr/share/graylog/data"
      - "graylog_tls:/usr/share/graylog/tls"
    restart: always

networks:
  graylog:
    driver: "bridge"

volumes:
  mongodb_data:
    external: true
  mongodb_config:
    external: true
  datanode_data:
    external: true
  graylog_data:
    external: true
  graylog_tls:
    external: true

3. What steps have you already taken to try and solve the problem?

I tried renewing the Data Node certificate using the web interface - the operation completed successfully but nothing changed. I did a few rounds of docker compose down / up and even rebooted the host. The errors stopped showing up this one time - I guess the new IP assigned to the Data Node container at that time matched the value the server was looking for. But I have had to reboot the host more times since and the errors always come back.

I searched for similar cases, found a few reports of VersionProbe errors (like 1, 2, 3 and 4), but nothing quite like this.

4. How can the community help?

My speculation: the preflight routine stored in MongoDB (or somewhere) the IP value that the datanode container had at that time, and now VersionProbe won’t use the container hostname when connecting to Data Node, just that one frozen IP, even though the hostname is included in the certificate SAN field.

Has anyone else seen this in their logs? Is this a bug? Do I need to freeze my container IPs (I would rather not to, if possible)? Can I make Graylog “forget” that one IP value and use the Data Node container hostname (configured in the Compose file) every time?

I upgraded to 7.1 and MongoDB 8.2 just recently. I was also making changes to container names and such and have no idea when these logs started appearing as I only just started shipping all my container logs to graylog today and noticed these in the logs.

The fix was simply setting a static IP address on the datanode container. I set a static IP on the graylog-server and graylog-mongodb containers as well but I assume it is just needed on the datanode.

After doing docker compose down and docker compose up -d I regenerated the certificate on the datanode and again ran docker compose down and docker compose up -d

No more error as the certificate presumably has the static IP listed now.

In my compose.yml I specify a network called compose which you can name whatever you want and it has a dynamic DHCP range from the .64 to .127 addresses on a /24 subnet.

networks:
  compose:
    driver: bridge
    enable_ipv6: false
    driver_opts:
      com.docker.network.host_ipv4: x.x.x.x # Optional, this forces traffic out of my preferred host IP
    ipam:
      driver: default
      config:
        - subnet: 172.20.100.0/24
          ip_range: 172.20.100.64/26
          gateway: 172.20.100.254

On any containers where I want a static IP I specify it with this. Use an address between the .1 and .63 or .128 and .253 address if you are using my network configuration above.

    networks:
      compose:
        ipv4_address: 172.20.100.x

Explicitly setting the hostname within the data node config could also help here if not wanting to rely on IP.

GRAYLOG_DATANODE_HOSTNAME
GRAYLOG_DATANODE_NODE_NAME

Thank you for sharing your fix. I would rather not use static IPs, but I’ll keep this in mind as a possible workaround.

Thank you for the tip. Unfortunately these did nothing.

Hey @SichuanPaoCai, this is, as you have discovered, a docker networking problem. Your container will get a new IP every time it starts. Proper solution is to configure the datanode service to use a FQDN configured in GRAYLOG_DATANODE_HOSTNAME and GRAYLOG_DATANODE_NODE_NAME, plus making sure this name is resolvable from your server or other services accessing the datanode. Then you need to renew the datanode certificate, to include this FQDN in its SAN. Then I’d restart everything and it should work.

Thanks @Tdvorak. Unfortunately, that didn’t solve the problem.

Here are the steps I took, just to be sure I didn’t misunderstand what you meant:

  1. Altered docker-compose.yml to include
    GRAYLOG_DATANODE_HOSTNAME: "datanode.my.url"
    GRAYLOG_DATANODE_NODE_NAME: "datanode.my.url"

  2. Did docker compose down and up, but Data Node wouldn’t start. Its log showed:
    2026-07-21T16:10:55.897 INFO [MongoDBPreflightCheck] Connected to MongoDB version 7.0.29
    2026-07-21T16:10:55.902 ERROR [PreflightCheckService] Preflight check failed with error: Configured hostname datanode.my.url is not bound to any address! Please configure your DNS so the hostname points to this machine
    ...

  3. So I changed the Data Node container hostname as well:
    hostname: "datanode.my.url"

    then did docker compose down and up again. This time it started as normal.

  4. Checked the IP of the Data Node container with docker network inspect graylog_graylog: 172.18.0.4. Also checked for name resolvability from the POV of the Graylog container with docker compose exec graylog curl -vk https[://]datanode[.]my[.]url[:]9200 and it looked fine:
    Host datanode.my.url:9200 was resolved.
    * IPv6: (none)
    * IPv4: 172.18.0.4
    * Trying 172.18.0.4:9200...
    * Connected to datanode.my.url (172.18.0.4) port 9200

    The error messages showed 172.18.0.3 was included in the certificate SAN but Hostname 172.18.0.4 not verified.

  5. Renewed the Data Node certificate. Data Node logs had successful renewal messages, but there was also an exception that showed the changed SAN field:
    2026-07-21T14:50:19.951 INFO [OpensearchProcessImpl] [2026-07-21T14:50:19,948][WARN ][o.o.w.FileWatcher ] [datanode.my.url] cannot notify file changes listener
    2026-07-21T14:50:19.951 INFO [OpensearchProcessImpl] OpenSearchException[java.security.cert.CertificateException: New certificates do not have valid SANs. Current SANs: [[[2, datanode.my.url], [2, localhost], [7, 0:0:0:0:0:0:0:1], [7, 127.0.0.1], [7, 172.18.0.3]]] new SANs: [[[2, datanode.my.url], [2, localhost], [7, 0:0:0:0:0:0:0:1], [7, 127.0.0.1], [7, 172.18.0.4]]]]; nested: CertificateException[New certificates do not have valid SANs. Current SANs: [[[2, datanode.my.url], [2, localhost], [7, 0:0:0:0:0:0:0:1], [7, 127.0.0.1], [7, 172.18.0.3]]] new SANs: [[[2, datanode.my.url], [2, localhost], [7, 0:0:0:0:0:0:0:1], [7, 127.0.0.1], [7, 172.18.0.4]]]];
    2026-07-21T14:50:19.952 INFO [OpensearchProcessImpl] at org.opensearch.security.ssl.SslSettingsManager.lambda$reloadSslContext$4(SslSettingsManager.java:123)
    2026-07-21T14:50:19.952 INFO [OpensearchProcessImpl] at java.base/java.util.Optional.ifPresentOrElse(Optional.java:196)
    2026-07-21T14:50:19.952 INFO [OpensearchProcessImpl] at org.opensearch.security.ssl.SslSettingsManager.reloadSslContext(SslSettingsManager.java:117)
    2026-07-21T14:50:19.952 INFO [OpensearchProcessImpl] at org.opensearch.security.ssl.SslSettingsManager$1.onFileChanged(SslSettingsManager.java:210)
    ...

  6. Did docker compose down and up once more… but no dice. Checked the Data Node IP (now 172.18.0.2), checked for name resolvability (Connected to datanode.my.url (172.18.0.2) port 9200). Now the errors read:
    2026-07-21 14:55:16,822 ERROR: org.graylog2.storage.versionprobe.VersionProbe - Unable to retrieve version from indexer node: Hostname 172.18.0.2 not verified:
    certificate: sha256/qiZf/I2AUsNZo0ORP/iFfOA6WfC+WfCplyHr6XdyMtc=
    DN: CN=datanode.my.url
    subjectAltNames: [127.0.0.1, 0:0:0:0:0:0:0:1, 172.18.0.4, localhost, datanode.my.url]. - Hostname 172.18.0.2 not verified:
    certificate: sha256/qiZf/I2AUsNZo0ORP/iFfOA6WfC+WfCplyHr6XdyMtc=
    DN: CN=datanode.my.url
    subjectAltNames: [127.0.0.1, 0:0:0:0:0:0:0:1, 172.18.0.4, localhost, datanode.my.url].

So it seems the certificate renewal process does indeed change the SAN field from
127.0.0.1, 0:0:0:0:0:0:0:1, <old-IP>, localhost, <old-hostname>
to
127.0.0.1, 0:0:0:0:0:0:0:1, <current-IP>, localhost, <current-hostname>,
but that doesn’t matter because after the new docker compose down and up the IP almost always changes again, which takes us back to Hostname <new-IP> not verified, because VersionProbe is using <new-IP> to talk to the Data Node instead of whatever hostname we set in the Compose file. Is this correct?

Thanks for your report and all the testing. I think you have done everything correctly. Now the only missing piece is to figure out why is the version probe (and generally your graylog server) trying to connect to the datanode and its openseach by using the IP and not the hostname. The IP in the SAN is not a problem, as long as there is the FQDN present, which is for you. The FQDN should be the stable and used identifier, not the IP.

Could you maybe show me the datanode.log, so we can see how is it initialized and why it is publishing the IP as the identifier?

Thanks!

@Tdvorak Here are the logs:

datanode_logs.pdf (358.4 KB)

Thank you for your help with this.

Thanks! I don’t see anything suspect in the datanode logs.

Maybe you could, as a test and workaround, configure the GRAYLOG_ELASTICSEARCH_HOSTS: "https://datanode.my.url:9200" to see if we can hardwire the datanode/opensearch hostname for the server and the problem disappear?

Hey @SichuanPaoCai ,

We found a bug related to your problem. Here’s the issue if you want to track the progress and future fix: Opensearch sniffer ignores configured hostname · Issue #26743 · Graylog2/graylog2-server · GitHub

The suggested workaround with setting elasticsearch_hosts should help you meanwhile.

Thanks for your help!

Thank you for looking into this and identifying the root cause, I really appreciate the effort.

I tried the workaround with GRAYLOG_ELASTICSEARCH_HOSTS, but Data Node did not come back up. There were lots of authentication errors in the log. The Graylog logs showed:

ERROR: org.graylog2.storage.versionprobe.VersionProbe - Unable to retrieve version from indexer node datanode.my.url:9200: unknown error - an exception occurred while deserializing error response: {}
com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'Authentication': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
at [Source: (okio.Buffer$inputStream$1); line: 1, column: 1]
at com.fasterxml.jackson.core.JsonParser._constructReadException(JsonParser.java:2675)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._reportInvalidToken(UTF8StreamJsonParser.java:3772)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._handleUnexpectedValue(UTF8StreamJsonParser.java:2843)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._nextTokenNotInObject(UTF8StreamJsonParser.java:867)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.nextToken(UTF8StreamJsonParser.java:753)
at com.fasterxml.jackson.databind.ObjectReader._initForReading(ObjectReader.java:356)
at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:2135)
at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1504)
at retrofit2.converter.jackson.JacksonResponseBodyConverter.convert(JacksonResponseBodyConverter.java:33)
at retrofit2.converter.jackson.JacksonResponseBodyConverter.convert(JacksonResponseBodyConverter.java:23)
at org.graylog2.storage.versionprobe.VersionProbeImpl.lambda$probeSingleHost$2(VersionProbeImpl.java:158)
at org.graylog2.storage.versionprobe.VersionProbeImpl.rootResponse(VersionProbeImpl.java:213)
at org.graylog2.storage.versionprobe.VersionProbeImpl.probeSingleHost(VersionProbeImpl.java:168)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
at java.base/java.util.ArrayList$ArrayListSpliterator.tryAdvance(Unknown Source)
at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.base/java.util.stream.ReferencePipeline.findFirst(Unknown Source)
at org.graylog2.storage.versionprobe.VersionProbeImpl.probeAllHosts(VersionProbeImpl.java:136)
at org.graylog2.storage.versionprobe.VersionProbeImpl.lambda$probe$1(VersionProbeImpl.java:116)
at com.github.rholder.retry.AttemptTimeLimiters$NoAttemptTimeLimit.call(AttemptTimeLimiters.java:78)
at com.github.rholder.retry.Retryer.call(Retryer.java:160)
at org.graylog2.storage.versionprobe.VersionProbeImpl.probe(VersionProbeImpl.java:116)
at org.graylog2.bootstrap.preflight.SearchDbPreflightCheck.runCheck(SearchDbPreflightCheck.java:50)
at com.google.common.collect.ImmutableList.forEach(ImmutableList.java:421)
at org.graylog2.bootstrap.preflight.PreflightCheckService.runChecks(PreflightCheckService.java:52)
at org.graylog2.bootstrap.ServerBootstrap.runPreFlightChecks(ServerBootstrap.java:183)
at org.graylog2.bootstrap.ServerBootstrap.beforeInjectorCreation(ServerBootstrap.java:151)
at org.graylog2.bootstrap.CmdLineTool.doRun(CmdLineTool.java:362)
at org.graylog2.bootstrap.CmdLineTool.run(CmdLineTool.java:287)
at org.graylog2.bootstrap.Main.main(Main.java:57)

After I removed that l, it started as normal. So I guess I’ll just ignore the error messages until the fix is out.