Skip to content

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.

  1. Check what you have: aws sts get-caller-identity (with the same --profile or AWS_PROFILE).
  2. Export keys, or name a profile: export AWS_PROFILE=audit, or vpcatlas discover --profile audit.
  3. 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 audit and 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 with ExpiredToken. Inside a scan these are recorded as error gaps, not as exit code 3, so a run that ends with many such issues is the sign. Raise --session-duration (up to the role's MaxSessionDuration), 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:AssumeRole on the role ARN.
  • The trust policy of the role must trust that identity, and when it has a sts:ExternalId condition the same value must go in --external-id (or VPCATLAS_EXTERNAL_ID).
  • When the trust policy demands MFA, add --mfa-serial and --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.

  1. Find the service and operation in the gap (CLI summary, the inventory, or the "Collection gaps" tab of the dashboard).
  2. Compare the role with the policy printed by vpcatlas iam-policy; the action is the service name and the operation in CamelCase, for example ec2:DescribeTransitGateways.
  3. 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 name vpcatlas.
  4. 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 --regions is also in --exclude-regions, or --exclude-regions covers every enabled region. Remove the exclusion.
  • not a region name: ... (exit 2). A region must look like eu-west-1. all is accepted by the dashboard variable VPCATLAS_REGIONS; on the command line, leave --regions out to scan every enabled region.
  • region_unavailable gaps 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 failed in the log. The role may not list regions, so the tool tries every region known to the installed boto3 and the disabled ones report region_unavailable. Add ec2:DescribeRegions (it is in the CoreEc2Network statement) or name the regions.
  • Empty pages. Regions without any resource get no page. Run without --regions to find where the network is, or read vpcatlas-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-1 is the biggest win. --exclude-regions does the opposite.
  • Lower the parallelism if you see throttled gaps: --concurrency 2. The default is 8 regions at a time, and at most 4 ec2 and 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.json and vpcatlas 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 HOME at 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, set LOCAL_UID and LOCAL_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:

  • 401 on every page: VPCATLAS_AUTH_PASSWORD is set. Use the user atlas (or VPCATLAS_AUTH_USER).
  • 429 on refresh: a manual refresh came before the minimum interval. The Retry-After header says how long.
  • The page loads but links break behind a reverse proxy: serve under a prefix with VPCATLAS_BASE_PATH=/atlas.
  • --cache or VPCATLAS_GRAPH_FILE points 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 .drawio and .lucid files and the whole set as a zip. Open the .drawio file in draw.io Desktop, which works offline.
  • To keep the in-page viewer offline, host the script yourself (take viewer-static.min.js from the diagrams.net project) on a server your users can reach, and point the dashboard at it with VPCATLAS_VIEWER_URL, an https:// 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 found on 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), use pipx install git+https://github.com/vpcatlas/vpcatlas or 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.sh stops with unsupported operating system. The script covers Linux and macOS. On Windows, download the archive from the releases page; tar -xzf unpacks it in a recent Windows 10 or 11.