Troubleshooting¶
Start from the verdict or the message you see. The quoted text on this page is what the CLI prints.
The scanner passes cloud SDK errors through without rewording them. A check that hits a
denied call shows the provider's own error inside its summary, such as
An error occurred (UnauthorizedOperation) from AWS, an HTTP 403 from Google, or
access denied reading <path> from Azure. There's no --verbose or --debug flag; the
check summary is the diagnostic.
A check says SKIP¶
SKIP means not assessed. The check didn't run. The summary says why.
| Summary | Cause | Fix |
|---|---|---|
No instance ID specified; skipping check. (and the same for bucket, KMS key, secret ARN, parameter path, EFS file system, DynamoDB table and DB instance) |
The scan wasn't given that target. | Pass the matching option. Scan inputs maps every check to its options. |
Need --gcp-instance, --gcp-zone, and --gcp-project; skipping check. |
GCP VM checks need all three. | Pass all three. |
Need --azure-subscription, --azure-resource-group and --azure-vm; skipping check. |
Azure VM checks need all three. | Pass all three. |
Need --azure-key-vault and --azure-key; skipping check. |
The Secure Key Release check needs the vault and the key. | Pass both. |
Need --instance-id and --pcr-baseline; skipping check. |
ENCLAVE-05 compares running PCRs with a baseline. | Pass --pcr-baseline baseline.json. |
No --attestation-doc supplied; skipping check. |
NITRO-ATT-02 and NITRO-ATT-03 read a captured attestation document. | Pass it with --nitro-attestation-doc (the message names the option without its nitro- prefix). |
Excluded by passive scan mode. |
You ran with --read-only, which skips checks that write or run commands. |
Expected. See what --read-only skips. |
Instance is neither a Nitro Enclaves parent nor an AMD SEV-SNP ... |
The check doesn't apply to this instance type. | Expected. |
A scan with any SKIP or ERROR ends with ... checks passed; coverage is incomplete. and
Skipped checks and errors remain unassessed. A skipped check is never counted as a pass.
A check says ERROR¶
ERROR means the check started but couldn't reach a verdict. It is never counted as a
pass, and it makes untrust scan exit 2.
Permission denied¶
The summary carries the provider's error, for example
Could not describe instance: An error occurred (UnauthorizedOperation) ... or
Access denied reading bucket policy: ....
- Open the check's page from the check list. Each page lists the API calls the check makes and the permission each one needs.
- Grant the missing permission to the scanning identity. The Required permissions page has an example policy or role for every platform.
- Scan again.
A Nitro check that can't call kms:DescribeKey says so directly:
could not verify ... uses a customer-managed CMK (grant kms:DescribeKey to the audit role).
A Google Cloud API isn't enabled¶
The check's summary includes Google's error naming the API, for example
SERVICE_DISABLED or accessNotConfigured. Enable that API in the project, wait a minute
and scan again. The scanner calls Compute Engine, Cloud KMS, IAM, Cloud Storage, Secret
Manager, Cloud Resource Manager and Access Context Manager. Which ones a check needs is on
its page.
Check raised an exception: ...¶
The check hit an error it doesn't handle. The rest of the message is the underlying error. Most often it's a missing or expired credential, or a resource name that doesn't exist in that region or project. Check the credentials and the target names, then scan again. If it persists, send the message to your untrust contact.
Not found¶
Instance <id> not found. or not found reading <path> (Azure) means the resource
doesn't exist where the scanner looked. On AWS, check --region: untrust scan and
untrust detect default to us-west-2 and ignore AWS_REGION. Pass --region
explicitly.
No credentials found¶
The scanner uses the credentials already present where it runs. It has no message of its own for missing credentials, so each check reports the SDK's error instead.
- AWS: the standard credential chain (environment variables,
AWS_PROFILE, an instance or workload role). Test withaws sts get-caller-identity. - GCP: Application Default Credentials. Run
gcloud auth application-default login, or attach a service account to the machine. Test withgcloud auth application-default print-access-token. - Azure: with the
azureextra installed,DefaultAzureCredential. Without it, the scanner asks the Azure CLI for a token:install 'untrust[azure]' or sign in with the Azure CLImeans neither is available.Azure CLI could not issue a token; run `az login`means the CLI isn't signed in.
untrust detect --platform azure-cvmreads the Activity Log live only withazure-mgmt-monitorandazure-identityinstalled. Otherwise it tells you to pass--azure-log-filewith exported Activity Log JSON.
Nitro host checks¶
The host and enclave checks run fixed commands on the parent instance through SSM Run Command.
| Summary | Cause | Fix |
|---|---|---|
Could not send SSM command: ... |
The instance isn't managed by SSM (agent stopped, no instance profile with SSM permissions, or no route to SSM), or the scanning identity lacks ssm:SendCommand. |
Check the instance appears in Systems Manager's managed nodes, and grant ssm:SendCommand on it and the AWS-RunShellScript document. |
SSM command did not complete within timeout. |
The command ran longer than about 30 seconds. | Check the agent's health on the instance and scan again. |
nitro-cli not available or no enclaves found. |
nitro-cli isn't installed on the parent, or no enclave is running. |
Install the Nitro Enclaves CLI and start the enclave before scanning. |
No enclaves are currently running. |
Nothing to measure. | Start the enclave. |
Could not locate an .eif file on the host to inspect. |
ENCLAVE-04 and ENCLAVE-07 inspect the enclave image file on the parent. | Keep the EIF on the parent instance. |
--read-only skips all of these checks.
The write probes pass even though I didn't grant write access¶
BOOTSTRAP-01 and
GCS-BOOT-02 try to write probe objects. A refused write
is the result the check wants, so without write permission they pass. That pass only shows
that the scanning identity can't write. BOOTSTRAP-02
and GCS-BOOT-01 read the bucket's policy to see who else
can. A transient storage error is reported as ERROR, not as a pass.
Exit codes¶
| Command | 0 |
1 |
2 |
3 |
|---|---|---|---|---|
scan |
No FAIL, no ERROR |
At least one FAIL, or no target given |
At least one ERROR |
|
scan --demo |
Always | |||
buildscan, iacscan |
Passed | Blocked | Incomplete or error | |
registry scan |
All verified | A confirmed failure | Not assessable | |
pack verify, ledger verify, ci verify |
Verified | Not verified, or the entry wasn't found | Missing input, such as --org |
Unsigned or unbound |
report-upload, collector run --once |
Sent | Refused or failed |
An invalid option also exits 2, the same code as an incomplete gate. CI treats both as a
failure, which is safe, but read the job log before concluding that a scan was incomplete.
ledger verify without --org exits 2 and prints
INTEGRITY VERIFIED, ORGANIZATION NOT CHECKED (pass --org): .... Pass --org with your
organization ID.
CI gates¶
2on a gate: the analysis was incomplete (an input over a size limit, an unparsable file, the time limit). The receipt's findings say which. It is never safe to treat as a pass. See the limits in CI gates.Plan and output paths must be different.iacscan --outputpoints at the plan file.Give one of --policy, --policy-url or one or more --image.registry scanneeds a trust policy or an image.- Upload refused for a build receipt:
--commitmust be the full commit SHA, and--run-idmust be the plain run ID (GitHub) or pipeline ID (GitLab), with no attempt suffix. They are compared with the OIDC token. - Uploading from Jenkins, Buildkite or another system: not supported. Only GitHub Actions and GitLab.com tokens are accepted. See CI systems.
Uploads and API calls¶
report-upload, api get and release verify print one of these when the service
refuses a request:
| Message | Meaning |
|---|---|
The request was refused (HTTP 401): the API key or token is invalid, expired or revoked. Create a new key in Settings › API keys. |
The key is wrong, expired or revoked. |
The request was refused (HTTP 403): this key's role cannot do it; ... |
The key's role can't do this. Create a key with a role that can. |
The request was refused (HTTP <code>). |
Any other refusal. The server's response body isn't shown. A 3xx means the URL redirected; the client never follows redirects, so use the exact https://<host>/v1/organizations/<org>/... URL. A 429 means too many requests: wait and try again. |
The request did not complete; inspect and retry. |
Network failure or the 30-second timeout. |
URL must be https://<host>/v1/organizations/<org>/<collection>[/...]. |
The --org-url is malformed. The organization ID is 32 hexadecimal characters. |
The request exceeds the size limit. |
The body is over 6 MiB. |
The attestation token is larger than 16 KiB; not sent. |
The --cs-attestation-token file is too large to be a token. |
The client doesn't retry. Requests time out after 30 seconds.
Collectors¶
| Message | Cause | Fix |
|---|---|---|
Not enrolled: <path> is missing. Run untrust collector enroll. |
No enrollment in this state directory. | Enroll, or point --state-dir (or UNTRUST_COLLECTOR_STATE) at the right directory. |
Already enrolled (<path>). Remove it to re-enroll. |
This host already has a key. | Remove the state file only if you mean to replace the host's identity. |
The untrust origin must use HTTPS. |
--origin isn't https://. |
Use the HTTPS origin. |
Could not reach untrust: ... |
Network, DNS or TLS failure. | Check outbound HTTPS. Use --ca-file if a proxy re-signs TLS. |
untrust answered 401: {"error": "Authentication required."} |
The enrollment token is invalid or expired, or the collector's key is unknown, revoked or its fleet is inactive. The service doesn't say which. | Check the host in the fleet; enroll again with a new token if it was revoked. |
untrust answered 409: {"error": "Bundle is stale or replayed."} |
The host clock is more than five minutes off. | Fix the time sync (NTP/chrony) on the host. |
untrust answered 409: ... That collector key is already enrolled. |
The same key was enrolled twice. | Remove the duplicate host in the fleet. |
untrust collector scan runs on Linux hosts; this is <platform>. |
Host checks run only on Linux. | Run it on the confidential host. |
Installing the service needs root (sudo). |
install-service writes a systemd unit. |
Run it with sudo. |
collector run logs report failed, will retry: ... and tries again at the next
interval. With --once, it exits 1 instead.
Demo and read-only mode¶
--demoruns against a built-in simulated deployment. It ignores--read-only, always exits0and marks its JSON"simulated": true. The console leaves simulated reports out of posture health.--read-onlyprintsREAD-ONLY MODE — active probes and host execution are excluded.Excluded checks are listed in the report undercoverage.mode_excluded_check_ids, and coverage always shows as incomplete. A--read-onlyscan can still exit2if another check errors.
Still stuck¶
Send your untrust contact the check ID, its summary, and the CLI version
(untrust --version). Remove target names and identifiers you don't want to share first.