Skip to main content
Each entry below is a failure that happened on a real installation, not a hypothetical. They are grouped by what you see, because that is what you have when something goes wrong.

The installation refuses to start

The value gate found <commit-sha>, registry.example.com or CHANGE_ME in an image repository or tag. It names every offending key.Fill them in your values file with the registry ROOTKey gave you and the released commit SHA of each service. Every workload needs both — not only auth-service.This is a refusal, not a failure. Without it the pods sit in ImagePullBackOff until the timeout, Helm rolls the release back, and the evidence is deleted with it.
One of three things is wrong, and the message names which:
  • PUBLIC_FILE_BASE_URL is unset or still the shipped example.
  • rootkey_public_host is unset.
  • The two name different hosts, or the base URL names a host no Ingress in your values file serves.
The third is the likely one, because the two values live in separate files. Set them to the same hostname:
The deploy account’s sudo asks for a password and the installer is not configured to supply one.
A host whose sudo uses a custom PAM prompt may still be unreachable this way. There, a NOPASSWD sudoers drop-in for the deploy account is the reliable path.
Ansible must be on the control machine — the one you run install.sh from — not on the target. Helm and kubectl are the opposite: the installer places them on the target and runs them there, so they do not need to be local in Scenario C.

The installation runs and something fails

Two different causes produce the same symptom.The tag does not exist in the registry. Confirm the exact tag is published, and that your values file and bundle/images.txt name the same one.The pull secret is missing or wrong. Every workload needs imagePullSecrets naming the Secret the installer created:
The describe output carries the registry’s actual response, which the pod status does not.
The credentials are valid but the account lacks pull permission on that specific repository. A 403 is an authorisation answer, not an authentication one — which is why the registry logs nothing that looks like a failed login.Confirm with ROOTKey that the account has been granted access to every repository the release names, not only the first one you tested.
The stateful stage checks three values before running any Helm command, and names the one that is missing:
  • rootkey_public_host — the inventory, or group_vars/all/main.yml.
  • rootkey_tls_secret_name — the Secret holding that host’s certificate.
  • BUCKET_NAME under rootkey_secret_data['aws-bucket'] in the vault, and not left as CHANGE_ME.
Nothing has been installed when this fires. Fix the value and re-run.
Prisma compares the checksum of every already-applied migration against the local file. A mismatch means the file changed after it ran.Do not edit the migration to match. Contact ROOTKey with the migration name — resolving it requires knowing which build wrote the original.A related warning is harmless: applied to the database but missing from the local migrations directory names migrations that ran on your database from an older build. It is a warning, not a failure, and the release notes say when to expect it.

The installation succeeded and something does not work

These are the ones worth reading before they happen. Each installs cleanly, reports success, and leaves the platform unusable in a way no log explains.
The most common silent failure. Everything else works: users register, files upload and anchor on-chain. Only fetching a stored object fails.There is nothing in the logs because nothing of ours failed. The platform returns a URL, and it is the user’s browser that tries to fetch it. If that URL names a host that does not exist, the request never reaches the cluster.Three commands identify it:
If step 2 prints the shipped example, the override is in the wrong place: it belongs under global.envOverrides, not inside a workload’s own section.
The Ingress works and the bucket has no anonymous read policy. A browser fetching an image sends no S3 credentials and never will.
Look for anonymous download enabled. If it says anonymous read NOT granted, anonymousRead was turned off. Re-run the MinIO chart — the policy is re-applied on every upgrade, so a helm upgrade restores it.
This grants read on objects only. It does not grant listing the bucket, so a key has to be known rather than discovered. It is the same posture as the cloud deployment, where the same objects are served by a CDN without credentials.
The contract seed did not run, so the smart-contract tables are empty and there is no contract to anchor against.
Watch the output. contratos semeados means it worked. skip: já há contratos means it was already done. skip: o fixture não veio no bundle means the seed file is missing from the release — contact ROOTKey rather than continuing, because the addresses cannot be invented.
CPU throttling. The limits shipped in the chart are sized for a shared multi-tenant cluster; on a dedicated host they become a brake with no beneficiary.Confirm it directly:
A rising nr_throttled and a large throttled_usec on a host that is mostly idle is the answer. On one measured case a service limited to 200m accumulated 84 throttling events and 4.69 seconds of throttled time during a 3-second test, with 6.7 cores free beside it.Raise the CPU limits in your values file and re-run the deploy stage.
Raise them in the values file, not with kubectl edit. An in-cluster edit is reverted by the next helm upgrade, and the symptom returns with no memory of why.
The plan seed has not run, or ran before the licence reconciled the catalogue.
It is re-runnable by design and must be re-run after the licence reconciles, and after every catalogue bump.
On a single-tenant deployment, public sign-up used to create a second organisation, and the licence reconciler then refused to materialise entitlements onto any organisation at all.Current releases refuse the sign-up instead: the invitation is the only front door, and somebody registering without one is told to ask for an invitation.If you are on an older build and already have two organisations, contact ROOTKey — resolving it means deciding which organisation owns the licence.
Both are internal routing or contract mismatches between services, and both were fixed in releases during 2026. If you see either, you are on an older build:
  • 502 on /api — the frontend’s nginx could not resolve the upstream service name.
  • 401 with missing_context on notifications — a service validated the acting user id as a UUID, and the identity provider does not issue UUIDs.
Upgrade. Neither has a configuration workaround.
It could not reach the Control Plane, served from its cached licence for the seven-day grace period, and reported itself healthy the entire time — because serving from cache is normal operation rather than an error.
Anything other than a 2xx means the egress allowlist does not contain control-api.rootkey.ai. Fix the firewall rule; the deployment recovers on the next renewal without intervention.

Certificates and DNS

Almost always the hostname rather than the certificate.
  • Does the name resolve from where the user is — the office network, the VPN? A record that exists only on the public internet does not help a user inside a closed network, and the reverse is also true.
  • Does the certificate cover the exact name being used, including any subdomain?
  • Is the TLS Secret in the release namespace? A Secret in default is invisible to an Ingress in rootkey.
This is why stored files are published as a path (<host>/files) rather than a files.<host> subdomain. A subdomain would need a second DNS record and a certificate covering the second name — two more chances for exactly this failure. The path rides the record and certificate the platform already uses.
No. The name only has to resolve for the people using the platform. A single-tenant installation on a closed corporate network needs an internal record and nothing public.A reseller deployment serving the reseller’s own customers is the other case, and there the record and the exposure are public. The installation is identical; the network around it is not.

Getting Help

When contacting ROOTKey support, include:
Plus the release version you installed and, if the failure was during the install, the output of the Ansible task that failed rather than the summary. The task name is what identifies the stage.
Never send your vault, your values file, or anything from hosts.ini. They hold credentials. If a value is relevant, name the key rather than pasting its content.

→ Back to On-Premise Installation