Open-Source Wikis

/

Trivy

/

How to contribute

/

Debugging

aquasecurity/trivy

Debugging

Trivy is a long pipeline (artifact → walker → analyzers → scanners → detectors → reports) that touches the network, the filesystem, container runtimes, and a couple of pre-built databases. When a scan misbehaves, narrowing the problem down quickly is mostly about turning on the right log level and finding the right cache to inspect.

Logging

Trivy uses a structured logger built on log/slog exposed through pkg/log/. The CLI honors several flags:

  • --debug — verbose log output (sets level to debug).
  • --quiet — suppress info-level output.
  • --no-progress — suppress the progress bar (useful in CI).
  • --trace — even more detail; enables logging of internal stages and walker decisions.

In code, log with log.Info, log.Debug, log.Warn, log.Error, or log.Fatal. Use log.String("key", value), log.Int("count", n), log.Err(err) to attach structured fields:

log.Debug("Analyzed file", log.String("path", path), log.String("type", string(typ)))

The logger is initialized in pkg/log/log.go. Test helpers can override it.

Tracing the scan pipeline

The most useful first step is --debug. It will show:

  • Which artifact handler was selected.
  • Which analyzers ran, and how many files each saw.
  • Which cache hits/misses happened.
  • The DB version that was loaded and its update behavior.
  • For client/server: the RPC endpoint, request, and response sizes.

For very fine-grained walker behavior use --trace.

Common reproduction recipes

A vulnerability is missing. Re-run with --debug and check for the package family detector. If the OS isn't detected, pkg/scan/service.go logs OS not detected and skips OS package scanning.

A vulnerability is a false positive. Use a VEX statement to suppress it locally, then file a bug. The VEX subsystem is in pkg/vex/.

An IaC rule misfires. Run with --trace and check the parsed configuration. The Terraform parser in pkg/iac/scanners/terraform/parser/ is the largest source of edge cases; it has a parser_test.go of nearly 3,000 lines for a reason.

A secret rule misfires. Built-in rules live in pkg/fanal/secret/builtin-rules.go. To temporarily disable a rule, write a custom secret config (pkg/fanal/secret/scanner.go reads it) and pass --secret-config.

Stale cache. Trivy's cache lives at ~/.cache/trivy/ by default. Wipe it (or specific blobs) with trivy clean --all (pkg/commands/clean/).

Working with a bad image

When an image scan fails or hangs, narrow down with the lower-level debug commands:

trivy image --debug --download-db-only        # only refresh the DB
trivy image --debug --skip-db-update IMAGE    # don't even check for updates
trivy image --debug --image-src docker IMAGE  # force the Docker daemon backend
trivy image --debug --image-src podman IMAGE  # force podman

The image source backends live in pkg/fanal/image/.

Working with the database

pkg/db/db.go shows the DB lifecycle. The DB is a bbolt file inside an OCI bundle. To inspect:

trivy --cache-dir /tmp/trivy-debug --debug --download-db-only image alpine:latest
ls /tmp/trivy-debug/db/

To download a specific version:

trivy --db-repository ghcr.io/aquasecurity/trivy-db:2 image alpine:latest

Working with the server

When something is wrong in client/server mode:

  1. Run the server with --debug and --listen :8080.
  2. Run the client with --debug --server http://localhost:8080.
  3. Compare the request/response logs. The Twirp protocol is HTTP+JSON by default, so tcpdump or a logging proxy works.

The RPC plumbing is in pkg/rpc/client/ and pkg/rpc/server/; the wire conversions are in pkg/rpc/convert.go.

Profiling

The CLI does not expose pprof directly, but you can wire it up locally:

import _ "net/http/pprof"
go func() { _ = http.ListenAndServe("localhost:6060", nil) }()

Add this to cmd/trivy/main.go for a one-off profile. The hot paths are typically in the walker (file IO) and in vulnerability detection (DB lookups).

Common errors

  • failed to download vulnerability DB — network or registry access; try --db-repository ghcr.io/aquasecurity/trivy-db:2 or set TRIVY_INSECURE=true for self-signed registries.
  • unknown OS — the analyzer registry could not detect the distribution. Add --debug and inspect the analyzer log lines.
  • policy initialization error — the Trivy Checks bundle could not be downloaded; pass --skip-policy-update or --config-policy <path> for an offline alternative.
  • no such directory: /trivy/cache — your --cache-dir does not exist; create it first.

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Debugging – Trivy wiki | Factory