Skip to content
Latchkey

GitHub Actions Artifact Has Unexpected Paths or Flattened Structure

An uploaded artifact has a different folder layout than expected because upload-artifact strips the least common ancestor of the matched paths, so the archive root may not be what you assumed.

What this error means

After download, files are at a different depth than in the workspace - a leading directory is missing or multiple inputs collapsed into one level - breaking scripts that expect a specific layout.

.github/workflows/ci.yml
path: |
  build/output/app
  build/output/meta.json
# common ancestor build/output is stripped; archive root is app + meta.json

Diagnose it: was the cache hit, and was it the right one?

Cache bugs split into three shapes and they need different fixes: the cache never saved, it saved but the key never matches on restore, or it restored a stale entry through a restore-keys prefix and is now poisoning the build. The step output tells you which one you have.

.github/workflows/ci.yml
- uses: actions/cache@v4
  id: cache
  with:
    path: ~/.npm
    key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-npm-

- name: What happened
  run: |
    echo "exact hit: ${{ steps.cache.outputs.cache-hit }}"
    echo "key used:  ${{ steps.cache.outputs.cache-matched-key }}"

Common causes

Least common ancestor stripped

upload-artifact removes the shared parent directory of all matched files, so the archive starts below that common path, not at the workspace root.

Multiple unrelated globs flatten

Mixing paths with different roots changes the common ancestor and can place files at an unexpected level on download.

How to fix it

Control the root with a single base path

Upload from a single base directory so the structure under it is preserved predictably.

.github/workflows/ci.yml
- uses: actions/upload-artifact@v4
  with:
    name: build
    path: build/output    # whole dir; structure under it is kept

Adjust expectations or restructure

  1. Account for the stripped common ancestor when reading the downloaded artifact.
  2. Stage files into one directory before uploading to fix the root.
  3. Avoid mixing globs with different parents in a single upload.

Cache limits that produce confusing failures

  • Repository cache is capped at 10 GB. Past that, GitHub evicts least-recently-used entries, so a large cache can silently stop persisting.
  • Caches are scoped by branch. A cache written on a feature branch is not visible to another feature branch, only to its base and its own descendants.
  • An entry not read for 7 days is evicted, so a rarely-run workflow effectively never has a warm cache.
  • Restoring a cache built for a different tool version is worse than a cold start, because you get a corrupted tree instead of a clean install. Always include the tool version in the key.

How to prevent it

  • Upload from a single base directory to keep a predictable layout.
  • Stage outputs into one folder before upload when structure matters.
  • Account for the least-common-ancestor stripping in consumers.

Frequently asked questions

What causes GitHub Actions artifact has unexpected paths or flattened structure?
There are 2 common causes: least common ancestor stripped and multiple unrelated globs flatten. upload-artifact removes the shared parent directory of all matched files, so the archive starts below that common path, not at the workspace root.
How do I fix GitHub Actions artifact has unexpected paths or flattened structure?
There are 2 fixes depending on which cause you have: control the root with a single base path and adjust expectations or restructure. Work through them in order, since the first is the most common.
What does GitHub Actions artifact has unexpected paths or flattened structure actually mean?
After download, files are at a different depth than in the workspace - a leading directory is missing or multiple inputs collapsed into one level - breaking scripts that expect a specific layout.
How do I stop GitHub Actions artifact has unexpected paths or flattened structure happening again?
Upload from a single base directory to keep a predictable layout. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card