Turn failures into useful evidence.
PackageMedic fails closed when analysis is incomplete. These checks distinguish a dependency finding from a restore, configuration, audit, Git, or CI operational problem.
First checks
dotnet --info
dotnet restore ./MySolution.sln
package-medic --version
package-medic doctor ./MySolution.sln --fail-on none --verbosity detailedCommon problems
Exit code 2 after restore
Likely cause: Restore failed, timed out, or returned an unusable dependency graph.
What to do: Run dotnet restore for the same target, inspect the sanitized NU/MSBuild evidence, verify feed access, and increase --restore-timeout only when the operation is legitimately slow.
--no-restore reports missing assets
Likely cause: At least one selected project has no usable obj/project.assets.json.
What to do: Run dotnet restore first or remove --no-restore. In diff mode, assets must be usable in both selected revisions.
Audit cannot obtain vulnerability data
Likely cause: The active SDK, feed, or advisory source is unavailable or produced unsupported output.
What to do: Check the installed SDK and NuGet sources, then run dotnet list package --vulnerable directly. PackageMedic returns 2 rather than claiming the graph is safe.
Deprecation audit cannot obtain data
Likely cause: The active SDK or configured package source is unavailable or produced unsupported output.
What to do: Run dotnet list package --deprecated --format json --output-version 1 directly. PackageMedic returns 2 instead of claiming that no package is deprecated.
Diff cannot find the Git reference
Likely cause: The reference is missing locally, unreachable, or CI checked out shallow history.
What to do: Ensure the base commit is present. In GitHub Actions, use actions/checkout with fetch-depth: 0 before auto mode or an explicit diff-base.
Auto mode rejects pull_request_target
Likely cause: That privileged event checks out the trusted base branch by default, so an automatic dependency diff could incorrectly compare the base against itself.
What to do: Run PackageMedic from an unprivileged pull_request workflow with fetch-depth: 0. Do not execute an untrusted PR checkout with privileged secrets.
The Impact Gate fails with unknown package source
Likely cause: allowedSources is configured, but NuGet restore metadata did not establish a trusted source for a changed package.
What to do: Restore normally from an allowed source, keep NuGet global-package metadata available to the runner, and verify the exact allowlist URL. Do not add a broad source only to silence PMI006.
The Impact Gate requires Package Source Mapping or locked mode
Likely cause: The repository opted into requirePackageSourceMapping or requireLockedMode and the evaluated project does not satisfy that boundary.
What to do: Configure packageSourceMapping for every active feed, or commit packages.lock.json and enable RestoreLockedMode. Change policy only through an intentional repository review.
Time Machine refuses to start on a dirty repository
Likely cause: The committed baseline cannot be reproduced while tracked or untracked checkout input is present.
What to do: Commit, stash, or intentionally remove all changes, then retry from a clean HEAD. PackageMedic does not copy uncommitted input into either snapshot.
Time Machine reports an ambiguous package declaration
Likely cause: The package has multiple effective declarations, a condition, an MSBuild expression, an external import, or only a transitive occurrence.
What to do: Select a narrower .csproj or solution with one literal direct or central declaration. PackageMedic refuses to guess which declaration should change.
Candidate restore is rejected by locked mode
Likely cause: The exact candidate changes the graph represented by the tracked packages.lock.json while RestoreLockedMode is enabled.
What to do: Treat the result as evidence that an intentional lockfile update is required. Do not disable locked mode merely to turn the simulation green.
A private feed is unavailable in Time Machine
Likely cause: Simulation snapshots do not inherit secret environment variables automatically.
What to do: Name only each required variable with repeatable --credential-env options. Verify the repository NuGet configuration and never paste live values into the command line.
Configuration or baseline is rejected
Likely cause: The file is malformed, contains an unknown property, escapes the repository boundary, or exceeds a size/count limit.
What to do: Validate .packagemedic.json against the published schema, use repository-relative paths, and regenerate baselines with the matching tool version.
SARIF is not visible in GitHub
Likely cause: Code Scanning is disabled or the workflow lacks security-events: write.
What to do: Enable GitHub Code Security where required and grant the minimum SARIF permission. The action still retains annotations and artifacts when upload is unavailable.
A project in the solution is reported missing
Likely cause: The solution references an absent file or a project outside the selected safe analysis root.
What to do: Repair the solution reference or select the correct repository root. PackageMedic intentionally rejects partial solution scans.
The scan is slow in a large repository
Likely cause: Restore, audit, or MSBuild evaluation dominates the workload.
What to do: Use a solution or narrower directory, exclude generated trees, keep assets warm, and tune maxParallelism within available CPU and memory. Use --no-restore only with verified assets.
When reporting a PackageMedic bug
- Include PackageMedic and
dotnet --infoversions. - Provide the smallest safe project or repository structure that reproduces the issue.
- Include the exact command, exit code, and sanitized detailed output.
- State whether restore, audit, configuration, baseline, or Git diff was enabled.
- Remove private feed URLs, usernames, tokens, and proprietary package names when necessary.
Use a public GitHub issue for normal bugs and private vulnerability reporting for suspected security issues.