Troubleshooting¶
Find your symptom, read the exit code, apply the fix. Put -v (or -vv for debug logging) before the command, as in vpcatlas -v discover, to see
every failed call as it happens, with its service, operation, region and error code.
Exit codes¶
| Code | Meaning |
|---|---|
0 |
Success. The run may still have recorded gaps; they are in the summary and the inventory. |
1 |
Failure that is not about credentials: no regions left to scan, a file that cannot be read or written, an AWS error that is not an authentication error. |
2 |
Bad usage: an unknown option, a malformed region, --mfa-serial without --mfa-token, both several --profile and --role-arn. The message says which. |
3 |
AWS credentials or access: credentials not found, expired or invalid, a profile that does not exist, a role that cannot be assumed. |
4 |
The scan finished with issues and --strict was set. |
Every error is one line starting with error: on standard error. The files are written only when the whole
scan succeeded.
Credentials¶
Unable to locate credentials or The config profile (...) could not be found¶
Exit code 3. The credential chain found nothing, or --profile names a profile that is not in
~/.aws/config or ~/.aws/credentials.
- Check what you have:
aws sts get-caller-identity(with the same--profileorAWS_PROFILE). - Export keys, or name a profile:
export AWS_PROFILE=audit, orvpcatlas discover --profile audit. - In a container, the credentials have to be passed in; see Docker cannot read ~/.aws.
ExpiredToken, or SSO: Token has expired and refresh failed¶
Exit code 3. Temporary credentials or an IAM Identity Center (SSO) session ran out.
- SSO profile: run
aws sso login --profile auditand repeat the command. - Temporary keys in the environment (
AWS_SESSION_TOKEN): get new ones; the tool cannot refresh keys it did not create. --role-arn: the tool refreshes the assumed-role credentials by itself, so this means the identity that assumes the role expired. Log in again. The exception is a run with--mfa-token: a one-time code cannot be reused, so when the scan outlasts--session-duration, the calls that follow fail withExpiredToken. Inside a scan these are recorded aserrorgaps, not as exit code 3, so a run that ends with many such issues is the sign. Raise--session-duration(up to the role'sMaxSessionDuration), narrow the scan with--regions, or run without MFA.
InvalidClientTokenId, SignatureDoesNotMatch¶
Exit code 3. The access key is wrong, deactivated or deleted, or the secret has a stray space or newline. Create a new key, or use a role or SSO instead of long-lived keys.
AccessDenied ... is not authorized to perform: sts:AssumeRole¶
Exit code 3. The role could not be assumed.
- The identity that runs the tool needs
sts:AssumeRoleon the role ARN. - The trust policy of the role must trust that identity, and when it has a
sts:ExternalIdcondition the same value must go in--external-id(orVPCATLAS_EXTERNAL_ID). - When the trust policy demands MFA, add
--mfa-serialand--mfa-token. - Check the account id and the role name in the ARN. A typo in the role name gives the same message.
The templates for the role are in IAM. With several --role-arn,
one role that fails stops the whole run.
ValidationError about DurationSeconds¶
Exit code 1. --session-duration is longer than the role allows. Keep it at or under the role's
MaxSessionDuration. When the identity that assumes the role is itself an assumed role (a chain, for example an SSO
role), AWS allows one hour at most: use the default of 3600.
Access denied on one API¶
Symptom. The run finishes, but a type of resource is missing from the diagrams, the summary shows a number
under "Issues", and the inventory ends with an "Issues and coverage gaps" section. With --strict the exit code is 4,
otherwise 0.
Cause. The role is not allowed to make a call, so a gap with code
denied was recorded. The log line has this form:
ec2.describe_transit_gateways in eu-west-1: denied (UnauthorizedOperation)
Fix.
- Find the service and operation in the gap (CLI summary, the inventory, or the "Collection gaps" tab of the dashboard).
- Compare the role with the policy printed by
vpcatlas iam-policy; the action is the service name and the operation in CamelCase, for exampleec2:DescribeTransitGateways. - If the policy already has the action, something else denies it: a service control policy, a permissions boundary,
a resource-based policy or an explicit
Deny. The message of the gap says "explicit deny" when that is the case. CloudTrail in the audited account shows the refused call with the session namevpcatlas. - Scan again. Gaps do not carry over between runs.
no regions left to scan, or nothing is drawn¶
error: ValueError: no regions left to scan(exit 1). Everything you passed in--regionsis also in--exclude-regions, or--exclude-regionscovers every enabled region. Remove the exclusion.not a region name: ...(exit 2). A region must look likeeu-west-1.allis accepted by the dashboard variableVPCATLAS_REGIONS; on the command line, leave--regionsout to scan every enabled region.region_unavailablegaps for a region you named. The region is not enabled for the account. Enable it in the account settings (opt-in regions need a few minutes) or remove it from--regions.ec2:DescribeRegions failedin the log. The role may not list regions, so the tool tries every region known to the installed boto3 and the disabled ones reportregion_unavailable. Addec2:DescribeRegions(it is in theCoreEc2Networkstatement) or name the regions.- Empty pages. Regions without any resource get no page. Run without
--regionsto find where the network is, or readvpcatlas-inventory.md.
Slow scans and throttling¶
Symptom. A scan takes many minutes, or the log shows throttled and the inventory has throttled issues.
Cause. The scan makes on the order of a thousand list calls for 17 regions. AWS limits calls per account and region, and other tools in the same account share that limit.
Fix.
- Narrow it:
--regions eu-west-1,us-east-1is the biggest win.--exclude-regionsdoes the opposite. - Lower the parallelism if you see
throttledgaps:--concurrency 2. The default is 8 regions at a time, and at most 4ec2and 2 other collectors run in one region. - Scan at a quiet time, and not while an inventory tool or a pipeline runs in the same account.
- Reuse a scan:
vpcatlas inventory --cache ./out/vpcatlas-graph.jsonandvpcatlas diagram --cache ...redraw without any AWS call. - Several accounts are scanned one after the other, so the time adds up. Split the accounts across runs if needed.
- On Lambda, set
VPCATLAS_REGIONS, scan on a schedule and serve a stored snapshot (see Deploy).
A throttled gap means the retries (8 attempts with backoff) ran out. Run again with a lower --concurrency.
Docker cannot read ~/.aws¶
Symptom. In the container: Unable to locate credentials (exit 3), or the dashboard says the first scan failed.
Or: Permission denied when writing to the output folder.
Cause. The image runs as an unprivileged user (uid 10001) with home /home/atlas. On Linux a mounted
~/.aws is owned by you, and its files are mode 600, so that user cannot read them. A
credential_process profile cannot work, because its helper binary is not in the image; an SSO profile works from the
mounted token cache only until that token expires.
Fix.
- Run as your own user and point
HOMEat the mount:
docker run --rm -p 127.0.0.1:8080:8080 \
--user "$(id -u):$(id -g)" -e HOME=/home/atlas \
-v "$HOME/.aws:/home/atlas/.aws:ro" \
vpcatlas/vpcatlas serve --host 0.0.0.0 --profile audit
- For SSO and other helper-based profiles, export short-lived keys on the host and pass them in:
eval "$(aws configure export-credentials --profile audit --format env)"
docker run --rm -p 127.0.0.1:8080:8080 \
-e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN \
vpcatlas/vpcatlas serve --host 0.0.0.0
- For output files, mount a folder you can write with
--user "$(id -u):$(id -g)", as in the README. - On Docker Desktop (macOS, Windows), make sure the folder is in the file sharing list.
- In
docker compose, setLOCAL_UIDandLOCAL_GID(export LOCAL_UID=$(id -u) LOCAL_GID=$(id -g)). - On ECS, EKS or EC2 you need no mount: the task, pod or instance role is found by itself.
If the browser cannot reach the dashboard at all, check that you passed --host 0.0.0.0 (the image does by default)
and that the port mapping is -p 127.0.0.1:8080:8080.
The dashboard shows no diagrams¶
Start with the status the page itself polls:
curl -s http://127.0.0.1:8080/api/status
What /api/status says |
Cause and fix |
|---|---|
"state": "scanning" |
The first scan is still running. A large account takes minutes; the diagrams appear when it ends. |
"has_snapshot": false and a last_error |
The first scan failed. The message is the same one the CLI prints; fix it as above (usually credentials). A manual refresh (POST /refresh) retries after a short wait. |
"has_snapshot": true but empty pages |
The scanned regions hold no resources, or VPCATLAS_REGIONS or --regions names the wrong ones. Without them the dashboard uses AWS_REGION or AWS_DEFAULT_REGION when set, which may be a single region. Use VPCATLAS_REGIONS=all to scan every enabled region. |
"has_snapshot": false, nothing scanning, on Lambda |
Lambda serves a stored snapshot and does not scan on a request when VPCATLAS_SCAN_ON_REQUEST=false. Run the scheduled scan once ({"atlas_action": "scan"}) and check VPCATLAS_SNAPSHOT_URI. |
"refresh_seconds": 0 |
The dashboard scans once, at start-up, and then only when you refresh. Set VPCATLAS_REFRESH_SECONDS (never below VPCATLAS_MIN_REFRESH_SECONDS, 300 by default). |
Other causes:
401on every page:VPCATLAS_AUTH_PASSWORDis set. Use the useratlas(orVPCATLAS_AUTH_USER).429on refresh: a manual refresh came before the minimum interval. TheRetry-Afterheader says how long.- The page loads but links break behind a reverse proxy: serve under a prefix with
VPCATLAS_BASE_PATH=/atlas. --cacheorVPCATLAS_GRAPH_FILEpoints to an old graph file: the dashboard serves that file instead of calling AWS.- The list of diagrams is there but the drawing area says "Loading the diagram": see the next section.
The diagrams.net viewer is blocked or offline¶
Symptom. The pages list, the inventory and the downloads work, but the drawing area stays on "Loading the
diagram...". The browser console shows a blocked or failed request for viewer-static.min.js.
Cause. The dashboard draws diagrams in the browser with the diagrams.net viewer script, which it loads from
https://viewer.diagrams.net/js/viewer-static.min.js. A machine without internet, a proxy, or a content security
policy that blocks that host stops it. Nothing else in the dashboard needs the internet.
Fix.
- You do not need the viewer to get the work done. The buttons download the
.drawioand.lucidfiles and the whole set as a zip. Open the.drawiofile in draw.io Desktop, which works offline. - To keep the in-page viewer offline, host the script yourself (take
viewer-static.min.jsfrom the diagrams.net project) on a server your users can reach, and point the dashboard at it withVPCATLAS_VIEWER_URL, anhttps://URL or an absolute path on the same host:
VPCATLAS_VIEWER_URL=https://static.example.internal/drawio/viewer-static.min.js vpcatlas serve
Check one page after the change; the dashboard itself does not serve this file.
- If a proxy is the problem, allow viewer.diagrams.net.
The binary is blocked by macOS or Windows¶
The release binaries are not code-signed or notarized in 0.1.0, so the systems warn about them. First verify the
download against the checksum on the release page (SHA256SUMS). The install script does this for you. Then allow it.
macOS Gatekeeper ("cannot be opened because the developer cannot be verified", or "Apple could not verify..."). Files
fetched with curl | sh normally carry no quarantine mark. Files downloaded with a browser do. Remove the mark:
xattr -d com.apple.quarantine ./vpcatlas
Or try to open it once, then open System Settings, Privacy & Security and choose Open Anyway next to the
message about vpcatlas.
Windows SmartScreen ("Windows protected your PC"). Choose More info, then Run anyway. Or unblock the file in PowerShell before the first run:
Unblock-File .\vpcatlas.exe
Some antivirus tools flag single-file programs built with PyInstaller. If yours does, compare the SHA-256 with the
release, then add an exception, or use the Python package (pipx install git+https://github.com/vpcatlas/vpcatlas) or the Docker image instead.
Other binary problems:
GLIBC_2.xx not foundon Linux. The binary needs a glibc as new as the one on the Ubuntu 22.04 build machine. On older distributions, and on Alpine (musl), usepipx install git+https://github.com/vpcatlas/vpcatlasor the Docker image.- The first start is slow. A one-file program unpacks itself to a temporary folder on each run; expect a second or two before the output starts.
install.shstops withunsupported operating system. The script covers Linux and macOS. On Windows, download the archive from the releases page;tar -xzfunpacks it in a recent Windows 10 or 11.