gameserver-observability · v0.1.1

Troubleshooting

The virtual environment was not created successfully because ensurepip is not available

Cause: scripts/test.sh creates a virtual environment, and Debian and Ubuntu ship the venv module’s pip bootstrap in a separate package.

Fix: install it (the package name follows the Python version, for example python3.12-venv) and run the script again. The failed run left an environment without pip behind; the script notices that and creates the environment again (… has no working pip; creating it again).

sudo apt-get install python3-venv
bash scripts/test.sh

error: … exists but does not belong to …; remove it or set TEST_VENV

Cause: the folder for the test environment ($TEST_VENV, see configuration) already exists and belongs to another user. scripts/test.sh refuses to run a Python that someone else could have put there.

Fix: check what the folder is, then delete it, or point TEST_VENV to a folder of your own, for example TEST_VENV="$HOME/.cache/gso-test-venv" bash scripts/test.sh.

ERROR: THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE

Cause: pip downloaded a file whose sha256 is not listed in requirements-test.txt. That happens when a proxy or mirror serves different files, or when the file was edited by hand.

Fix: install from PyPI directly. If requirements-test.in changed, compile the file again as shown on the toolchain page instead of editing hashes by hand.

sha256sum: WARNING: 1 computed checksum did NOT match

Cause: the downloaded promtool tarball is not the file the pin expects: the download broke, or the version and the sha256 were changed separately.

Fix: download again; when bumping promtool, take the version and the sha256 from the same release’s sha256sums.txt and change both in ci.yml and toolchain.md.

promtool: command not found

Cause: scripts/check_promtool.sh expects promtool on the PATH.

Fix: install it as shown on the toolchain page and add its folder to the PATH, for example PATH="$PWD:$PATH" bash scripts/check_promtool.sh.

server returned HTTP status 401 Unauthorized on the fxserver_perf target

Cause: the server refused the credentials. It compares the whole Authorization header, so the user in basic_auth.username and the content of the password file must equal sv_prometheusBasicAuthUser and sv_prometheusBasicAuthPassword exactly. Prometheus strips leading and trailing whitespace, including the newline, from the password file and keeps the spaces inside the password, so a server password that starts or ends with a space never matches.

Fix: compare the values (choose a password without leading or trailing spaces), then check that Prometheus can read the file (its user needs read access to /etc/prometheus/secrets/fxserver_perf) and that the server was restarted after the variables changed. With the luminare.gameserver collection, the server’s values are fxserver_perf_user and fxserver_perf_password, or the user and password of the txadmin role’s txadmin_prometheus_basic_auth when that toggle is enabled (installation).

sample limit exceeded on a target

Cause: the target served more series than the job’s sample_limit, so Prometheus dropped the whole scrape. With the shipped configs this happens only when a server version or an exporter version serves many more series than measured in the cardinality budget.

Fix: look at what the target serves (for an exporter job, open its /probe URL with the same module and target), then raise the limit in the scrape job if the new series are expected.

Failed to fetch JSON response in the json_exporter log, target answers 503

Cause: json_exporter could not get a 2xx answer from dynamic.json or info.json: the server is down, the address is wrong, or the server refused the request. A 403 with the body Nope. comes from sv_requestParanoia when a proxy between json_exporter and the server adds a Via header (level 1 or higher); a 429 means that address sent info.json more requests than the server allows (4 per second, burst 10).

Fix: scrape the server directly (no proxy), or lower sv_requestParanoia; keep the JSON jobs at 30 seconds or more.

probe_success{module="http_401_expected"} is 0

Cause: /perf/ answered without credentials, because neither sv_prometheusBasicAuthUser nor sv_prometheusBasicAuthPassword is set on the server.

Fix: set both (configuration) and restart the server; see the runbook.

Prometheus → Status → Rules shows no group fxserver-alerts

Cause: the rule files are not loaded: rule_files is missing from prometheus.yml, its path does not match where the files are, or Prometheus was not reloaded. A file that does not parse stops the reload, and Prometheus logs the error and keeps the old rules.

Fix: check the path (rule_files: [/etc/prometheus/rules/*.yml] with the files installed as in Installation), run promtool check config /etc/prometheus/prometheus.yml (it also checks the rule files it names) and reload Prometheus.

An alert names no game server (server is empty)

Cause: the alert reads a series without the server label: the node_exporter or mysqld_exporter job, or a target of the pack’s jobs, has no server label.

Fix: add the label to every target of those jobs, with the name of the game server it belongs to (configuration).

Cause: the job fxserver_versions is not loaded (prometheus/scrape/versions.yml is not in scrape_config_files), or json_exporter cannot fetch the version list: no outbound HTTPS from the Prometheus host, no DNS, a proxy in between, or missing CA certificates. json_exporter then logs Failed to fetch JSON response and the target answers 503.

Fix: check up{job="fxserver_versions"}, then ask json_exporter directly on the Prometheus host:

curl -fsS 'http://127.0.0.1:7979/probe?module=fxserver_versions&target=https://changelogs-live.fivem.net/api/changelog/versions/linux/server'

It must print fxserver_recommended_build with a build number. Allow outbound HTTPS for json_exporter, or, behind a proxy, set proxy_url in the module’s http_client_config.

check_pack: … [parse] line N: …

Cause: scripts/check_pack.py reads only the YAML the configs need. Values such as yes, no, on or off, numbers with a leading zero, dates, block scalars (|, >), anchors, values that continue on the next line, and : inside an unquoted value in [...] are refused instead of guessed.

Fix: quote the value or write it on one line, and use true/false for booleans, as the other configs do.

smoke_exporters: port(s) in use on 127.0.0.1

Cause: the end-to-end run needs the ports of the shipped configs: 30120 (fake server), 7979 (json_exporter) and 9115 (blackbox_exporter).

Fix: stop what uses them, or run the script in a container without published ports, for example docker run --rm --network none -v "$PWD":/repo:ro -v "$PWD/bin":/opt/bin:ro python:3.13-slim python3 -I /repo/scripts/smoke_exporters.py --bin-dir /opt/bin.

Demo stack: Bind for 127.0.0.1:3000 failed: port is already allocated

Cause: docker compose -f demo/docker-compose.yml up publishes Grafana, Prometheus and the simulated server on 127.0.0.1:3000, 9090 and 30120 of the Docker host, and another program or container already uses one of them (the message names the port).

Fix: remove the half-started stack with docker compose -f demo/docker-compose.yml down -v, then choose free host ports with GSO_DEMO_GRAFANA_PORT, GSO_DEMO_PROMETHEUS_PORT and GSO_DEMO_GAME_PORT (demo stack). scripts/smoke_demo.py picks free ports itself.

Demo stack: Grafana and the simulated server stopped answering

Cause: the services share the network namespace of the Prometheus container. When only that container was recreated (for example with docker compose up -d --force-recreate prometheus), the others are left without a network.

Fix: run docker compose -f demo/docker-compose.yml up -d; it recreates them in the new namespace (ADR 0020).

smoke_demo: the Compose project … already has N container(s)

Cause: an earlier run of scripts/smoke_demo.py was stopped before it could remove its stack, or a stack of yours uses the same project name. The script never removes containers it did not create.

Fix: if they are left from an earlier run, remove them with docker compose -p gameserver-observability-demo-smoke -f demo/docker-compose.yml down -v; otherwise pass another --project-name.

A dashboard panel shows “No data”

Cause: the panel’s series are not in the selected data source: the Data source selector points to another Prometheus, the job for that row is not scraped (node_exporter for Host, mysqld_exporter for MariaDB, cloudflared for the tunnel, the optional fxserver_tunnel job for the admin hostname), or its targets have no server label, so the Game server filter does not match them. The Game server selector is empty when the job fxserver_perf has no target with a server label.

Fix: choose the data source that has the pack’s series, and give every target of those jobs the server label of its game server (configuration). Panels of exporters you do not run stay empty; that is expected.

lint_dashboards: … [shareable] missing or not the copy of …

Cause: a dashboard in grafana/dashboards/ changed, and its copy in grafana/dashboards/shareable/ was not written again.

Fix: run python3 scripts/lint_dashboards.py --fix, then the check again, and commit both files. A finding [parse] … not in the repository's format has the same fix.

FXServerArtifactOld never fires and Build age shows “No data”

Cause: the two build alerts and the Build age panel read fxserver_artifact_build and fxserver_artifact_installed_timestamp_seconds, which node_exporter’s textfile collector reads from fxserver_artifact.prom on the game server. The file is missing (the fxserver role of the luminare.gameserver collection writes it only with fxserver_textfile_dir set), node_exporter reads another folder, or its job has no server label. Without the series the alerts stay silent instead of failing.

Fix: on the game server, check that the file exists in the folder passed to node_exporter’s --collector.textfile.directory; then query fxserver_artifact_build in Prometheus, which must return one series per game server with its server label (configuration).

Alerts fire in Prometheus, but nobody gets a notification

Cause: the pack evaluates alerts but sends none: Prometheus needs an alerting block that names your Alertmanager, and the Alertmanager a route for the alerts’ labels (ADR 0023).

Fix: add both as shown in configuration. curl -fsS http://127.0.0.1:9090/api/v1/alertmanagers lists the Alertmanagers Prometheus sends to, and amtool config routes test --config.file=alertmanager.yml severity=critical server=game-01 prints the receiver an alert would reach.

Quickstart: curl: (7) Failed to connect to 127.0.0.1 port 30120

Cause: the demo stack is not running, for example because docker compose up stopped at a port that was already taken, or it was started with another game port (GSO_DEMO_GAME_PORT).

Fix: docker compose -f demo/docker-compose.yml ps shows what runs; start it again on free ports (demo stack) and send the request to the game port you chose.

Still stuck?

Search the issues, then ask in the repository’s Discussions. Never post secrets, keys, IP addresses, hostnames or player data; redact logs before you paste them.

Not affiliated with or endorsed by Cfx.re, Rockstar Games or Take-Two.

docs/troubleshooting.md on GitHub

Licensed under Apache-2.0. Source: luminare-dev/gameserver-observability at v0.1.1.