Skip to content

Troubleshooting

The common surprises during install, in the order you tend to hit them.

Google Workspace setup

Org policy blocks service-account key creation

When you click Add key → Create new key → JSON in Google Workspace setup §3, the dialog refuses with:

An organisation policy that blocks service accounts key creation has been enforced on your organisation.

This is the GCP org constraint iam.disableServiceAccountKeyCreation. It's a defensible security default — Google recommends it — but it blocks ARIS's current install path: core reads the service-account JSON from disk and exchanges it for a Workspace API token via DWD.

Three paths forward, in order of preference.

This is the simplest path: the override itself is the scope, so no tag or condition is needed.

  1. With the ARIS project selected in the top-of-page resource picker, open IAM & Admin → Organisation policies.
  2. Find Disable service account key creation. Open it.
  3. Manage policy. Confirm Applies to: Project '\<your-aris-project>' at the top.
  4. Set Policy source to Override parent's policy.
  5. Under Rules, on the New rule card, set Enforcement to Off.
  6. Leave Add condition alone — you don't need one. (The "Condition builder" is for narrowing the exception further inside this project, e.g. only for tagged resources. ARIS doesn't need that — you want the override to apply project-wide.)
  7. Set policy.

Re-run §3 — the Create new key button now works for the ARIS project only. Every other project in the org keeps inheriting the org-level "On".

If you don't have Org Admin or Project Owner access, send the policy page link to whoever does and ask for the project-level override above (not an org-wide toggle). That keeps org-wide protection intact while unblocking ARIS.

B. Use a pre-existing key

Keys created before the policy was enforced are not revoked retroactively. Check the service account's Keys tab. If you (or a colleague) generated a JSON key earlier and still have the file, use it — set ARIS_GOOGLE_SERVICE_ACCOUNT_KEY_FILE to that path and skip the Add key step entirely.

C. Wait for keyless auth (no current support)

ARIS today reads ARIS_GOOGLE_SERVICE_ACCOUNT_KEY_FILE as a JSON key on disk. Keyless alternatives (Workload Identity Federation, ambient Application Default Credentials with impersonation) are not wired into core in the current MVP. If your security posture forbids JSON keys org-wide and an exception is off the table, this is a feature request, not a config change. The DWD authorisation in §4 is orthogonal — it stays the same regardless of how the service-account token is obtained — so the feature is a small swap of the credential source, not a re-architecture.

Boot

core exits at boot with missing ARIS_AUTH_TOKEN_SECRET ...

.env is incomplete or hasn't been picked up by Docker Compose.

  • Confirm .env exists at the repository root (the same directory as compose.yml). Compose only reads .env from the project root, not from arbitrary subdirectories.
  • Confirm the variable in question is non-empty in .env and not commented out.
  • If you populated .env while compose was already running, you need docker compose down && docker compose up — running containers do not pick up .env changes.

core exits at boot with ARIS_AUTH_TOKEN_SECRET must be at least 32 bytes

Your secret is too short. openssl rand -hex 32 produces 64 hex characters, which is 32 bytes — exactly the minimum. Anything shorter is rejected at boot to prevent issuing weak tokens.

core boots but the first sync errors out with a Google API failure

  • unauthorized_client or access_denied → domain-wide delegation isn't authorised for the service account, or the wrong scopes are listed. Re-check Google Workspace setup §4. The two scopes must be the read-only variants exactly as listed there.
  • invalid_grant → the delegate email isn't a real Workspace user, or it doesn't have admin permissions to read the directory. Use a Super Admin account.
  • key file not found / invalid private key → the service-account JSON path in .env is wrong, or the file isn't readable by the user running Docker. Confirm with the verification command in Configure §4.

Postgres healthcheck never passes

docker compose logs db | tail -30

Most often: POSTGRES_PASSWORD contains a special character that confused the shell. Wrap the value in single quotes in .env:

POSTGRES_PASSWORD='my$pecial!password'

Login

/login?error=UnknownIdentity

Your Google account has no authentication_identity row in ARIS. Two causes:

  1. Sync hasn't run yet, or hasn't run since you joined the Workspace domain. Check docker compose logs core | grep 'directory.sync.run report'. If you see a recent run with errors non-zero, fix the sync error first.
  2. Your account is in a different Workspace domain than ARIS_GOOGLE_DOMAIN. ARIS only links identities for users in the configured domain.

/login?error=PersonInactive

A person row exists but its status is not active — usually external_deleted (the user disappeared from a previous Workspace sync) or deactivated (the user is Suspended=true or Archived=true in Workspace).

To recover: reactivate the user in Google Workspace and wait for the next sync (default 1 hour) or restart core to trigger a boot sync.

/login?error=EmailUnverified

Google reports email_verified=false for the account. Workspace-managed accounts are always verified; this typically means you tried to log in with a personal Gmail address that isn't part of your Workspace domain. Use a Workspace user instead.

/login?error=AccessDenied

The Google user is not allowed to use this OAuth client.

  • The OAuth consent screen is set to Internal but the user is not in the configured Workspace domain.
  • The OAuth consent screen is set to External / Testing and the user is not on the test-user list.

Either move the user into the right Workspace domain or change the consent screen to Internal (recommended for production).

/login?error=Callback

NextAuth's catch-all error. Two common causes:

  1. Redirect URI mismatch. The URI registered on the OAuth client must exactly match ${NEXTAUTH_URL}/api/auth/callback/google. Mismatch (e.g. http vs https, or a port typo) produces a Google-side rejection that NextAuth surfaces as Callback.
  2. DB lookup threw. Inspect docker compose logs web | grep 'signIn: identity lookup failed'. Most likely the web container can't reach Postgres — see § "I'm in the admin group..." below for connectivity checks.

Redirect loop between / and /login

NEXTAUTH_SECRET is missing or different across container restarts. Confirm:

docker compose exec web env | grep NEXTAUTH_SECRET

The value should be present and stable. If you regenerate it, every existing session is invalidated and operators have to re-login.

Authorisation

I'm in the admin group but only got read

Three possible causes, in order:

  1. Sync hasn't seen the membership change yet. Group membership changes only take effect on the next directory sync. Either wait ARIS_DIRECTORY_SYNC_INTERVAL or restart core (docker compose restart core) to trigger a boot sync.
  2. Group name mismatch. ARIS looks for the literal group address aris-admin@<ARIS_GOOGLE_DOMAIN> (and aris-auditor@...). A group called aris-admins or [email protected] does not match. Check group membership with:
    docker compose exec db psql -U aris -d aris -c \
      "SELECT user_id, group_ids FROM employment_state WHERE valid_to IS NULL;"
    
  3. The web container can't reach core. Hit curl http://localhost:8080/v1/whoami directly with a hand-minted token (see First login §5) — if that returns admin scopes but the UI shows read-only, the bug is in the web→core path.

/v1/whoami returns 401 invalid bearer token: invalid token signature

core and web were given different ARIS_AUTH_TOKEN_SECRET values. Confirm both containers see the same value:

docker compose exec core env | grep ARIS_AUTH_TOKEN_SECRET
docker compose exec web  env | grep ARIS_AUTH_TOKEN_SECRET

The compose file passes the same .env value to both — if they differ, you started one container before populating .env and the value is stale.

Collector

core does not log ingest listening

Collector ingest is disabled unless ARIS_INGEST_GRPC_ADDR is set. Confirm the core container sees the variable and the three required TLS file paths:

docker compose exec core env | grep ARIS_INGEST

If the TLS files are mounted from the host, remember that ARIS_INGEST_SERVER_CERT_FILE, ARIS_INGEST_SERVER_KEY_FILE, and ARIS_INGEST_CLIENT_CA_FILE are container-internal paths.

aris-collector validate-config rejects the key file permissions

Collector private keys must not be group/world readable on Unix. Fix the key mode:

chmod 600 /etc/aris/collector/collector.key

The same rule applies to core's ingest server key.

host_id ... does not match client certificate identity

In secure mode, the collector's host_id is derived from the client certificate's single DNS or URI SAN identity. Either remove the explicit host_id from collector.yaml or set it exactly to that SAN. Multi-identity collector certificates are rejected.

Forwarder shows last_err and no acks

Check these in order:

  1. The collector can reach forwarder.core_endpoint on the network.
  2. forwarder.mtls.server_name matches a DNS SAN on core's ingest server certificate.
  3. forwarder.mtls.server_ca_path contains the CA that issued core's ingest server certificate.
  4. Core's ARIS_INGEST_CLIENT_CA_FILE contains the CA that issued the collector client certificate.

Use:

aris-collector status --config /etc/aris/collector/collector.yaml

sent increasing with flat acked usually means core accepted the connection but is not acknowledging records. Inspect core logs for ingest errors.

When you really need to start over

docker compose down -v          # deletes the DB volume too
rm .env                         # if you want to redo configuration
docker compose up --build       # full clean install

Anything not covered here belongs in a support ticket. Capture docker compose logs --no-color > aris-logs.txt and include it.