No files were found with the provided path in upload-artifact
The message no files were found with the provided path is not a statement about your artifact, it is the result of a glob: actions/upload-artifact expanded its path input against the runner filesystem and got an empty list. Whether that ends the job, warns, or says nothing is decided by if-no-files-found, and the default lets the build stay green.

What this error means
The same sentence appears whether the step warned, failed or stayed silent, because all three branches emit identical text at different severities. The line below is the error one, from a run that had set if-no-files-found: error. At the shipped default the upload step is yellow rather than red, the job finishes, and the run looks fine. Minutes later a different job fails because the artifact it wanted is not there, and that is the failure people report. The line names an absolute path on the runner, which is worth reading carefully: it is the path the action resolved, not the one you typed.
##[error]No files were found with the provided path: /__w/_temp/release-assets. No artifacts will be uploaded.A minimal workflow that produces it
This file is written for this page and has never been run. The build step changes directory and writes relative to the package it built, so the files land in packages/app/dist. The upload names dist, resolved against the workspace root, where nothing exists. Nothing in the run is red: the build passes, the upload warns, the artifact is absent.
name: ci
on:
push:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: npm ci && npm run build
working-directory: packages/app
- uses: actions/upload-artifact@v7
with:
name: site
path: distCommon causes
The build wrote to a different directory than the upload reads
The ordinary case, and the one the illustrative workflow shows. A working-directory on the build step, a build tool with its own output root, or a monorepo where each package writes into itself all put files where the upload path does not reach. The absolute path in the message is the whole diagnosis.
The step that should have produced the files did not run
A conditional step that evaluated false, a cached step that short-circuited, or a build that failed under continue-on-error all leave the directory empty. This looks identical in the log to a wrong path, which is why listing the directory before the upload is worth the two seconds.
Everything the pattern matched is a directory or a hidden file
Directories are filtered out of the match list, so a tree of empty directories uploads nothing. Hidden files have been excluded by default since version 4.4.0, so a path containing only dotfiles, a .next build that is being uploaded wholesale, or a coverage directory whose entries begin with a dot now matches zero files where it once matched many.
The path is right for a shell and wrong for an action
Tilde expansion, environment variables in shell syntax and relative paths borrowed from a run: block are the recurring near misses, because the action has its own handling for all three and it is not the shell one. In a container job the workspace is mapped as well, so even an absolute path can resolve differently between steps.
How to fix it
Make the empty match the failure
Do this first, before diagnosing anything. With if-no-files-found: error the run goes red on the step that has the path in front of it, rather than in a different job with a message about a missing artifact. On any upload a later job consumes, this is the default to write.
- uses: actions/upload-artifact@v7
with:
name: site
path: packages/app/dist
if-no-files-found: errorPrint the directory from the same place the action will read it
The cheapest diagnostic is a listing taken from the workspace, which is where the action resolves a relative path. Doing it in the build step working directory proves nothing, because that is the frame the action does not use.
ls -la "$GITHUB_WORKSPACE"
find "$GITHUB_WORKSPACE" -maxdepth 3 -name "dist" -type dInclude hidden files only when you mean to
If the files you expected begin with a dot, the exclusion added in version 4.4.0 is why they are missing. Turning it back on is one input, and it is worth narrowing the path at the same time: the reason for the change was that whole-directory uploads were carrying credentials out of a build, and re-enabling it over a broad path reinstates exactly that risk.
- uses: actions/upload-artifact@v7
with:
name: coverage
path: packages/app/coverage/.tmp
include-hidden-files: true
if-no-files-found: errorGive multiple paths deliberately, and check the root
Several paths are allowed, one per line, with exclusions prefixed by an exclamation mark. With more than one the action recalculates the artifact root as their least common ancestor and logs that it has, so the layout inside the artifact changes. Read that line after adding a second path.
- uses: actions/upload-artifact@v7
with:
name: reports
path: |
packages/app/dist
packages/app/coverage
!packages/app/dist/**/*.map
if-no-files-found: errorThe same sentence at three severities
The action emits this text from a three-way switch on if-no-files-found, and the string is identical in all three branches. That is why a search for the message finds people describing it as a warning, as an error, and as something they never saw: one code path with a different reporting function on the end.
The default is warn, which the README documents as "Output a warning but do not fail the action". That default is why this error is nearly always discovered somewhere else: nothing fails, and the run holds one artifact fewer than it should until something tries to read it.
case NoFileOptions.warn:
core.warning(`No files were found with the provided path: ...`)
case NoFileOptions.error:
core.setFailed(`No files were found with the provided path: ...`)
case NoFileOptions.ignore:
core.info(`No files were found with the provided path: ...`)if-no-files-found | How the line is logged | What the job does |
|---|---|---|
warn (the default) | A warning annotation | Passes, with no artifact |
error | An error annotation | Fails on the upload step |
ignore | An ordinary info line | Passes, with nothing to notice |
What the glob does and does not count
The search is a glob, and two of its rules produce an empty result that looks like it should not be. Directories are removed from the match list after globbing, so a pattern matching only an empty directory matches no files. Hidden files are excluded unless you ask for them, which changed in version 4.4.0: the release notes call it a breaking change made so credentials are not swept into an artifact by accident, and it is why a path holding only dotfiles now uploads nothing.
A third rule is about roots rather than matches. One path makes its own search path the artifact root; several paths make the action calculate their least common ancestor and use that, which quietly changes the directory structure inside the artifact. That never causes an empty match, but it explains the near miss where the upload succeeds and the layout is not what the download expects.
Then there is the path itself. working-directory applies to run: steps and not to an action, so a relative path on the upload resolves from the workspace root whatever the build step did. In a container job it is stranger: the report quoted above shows one step listing the file at one absolute path and the upload, in the same job, reporting an empty match at a different absolute path for the same directory. That report is open, and the lesson is to make the path explicit rather than trust two steps to agree.
Why there is no recorded run on this page
There is no runner failure here to record. The glob returns an empty list deterministically for as long as the files are not where the pattern points, so a recorded log would show the same sentence this page already quotes and add nothing. There is nothing to repair either: a runner cannot invent a build output, and retrying produces the identical empty match. The workflows are illustrative.
How to prevent it
- Write
if-no-files-found: erroron every upload that another job depends on. - Use workspace-relative paths in an action, and keep
working-directoryforrun:steps. - List the output directory in the step before the upload while a workflow is new.
- Name hidden files explicitly rather than re-enabling them across a whole build directory.
Frequently asked questions
Why does upload-artifact say no files were found when the files exist?
path on the action is resolved against the workspace root, and working-directory on an earlier run: step does not move it. Compare the absolute path printed in the message with a listing taken from GITHUB_WORKSPACE, not with what the build step saw.Should if-no-files-found be warn or error?
warn, which keeps the job green and no artifact, so the first red step is a download failure somewhere else entirely. Leave it at warn only for genuinely optional output, such as a debug bundle that is uploaded on failure and is not always produced.Why did upload-artifact stop uploading my dotfiles?
include-hidden-files: true to restore the old behavior, and narrow the path at the same time so you are not re-opening the problem the change was made to close.Does an empty directory count as a file for upload-artifact?
Related guides
References
- actions/upload-artifact README: inputs, limitations and the no-files behavior
- A report where the previous step lists the file and the upload matches none
- Release notes for the version that stopped including hidden files
- GitHub Actions: store and share data with workflow artifacts
- GitHub Actions documentation