Skip to content

Self-repository actions stage the entire repository and can fail on unrelated dangling symlinks #4631

Description

@garysassano

Main

Describe the bug

Using the self-repository action syntax:

- uses: $/.github/actions/example

causes the runner to download and stage the entire repository before the action executes, rather than only the referenced action directory.

This means that a tracked dangling symbolic link elsewhere in the repository can make action preparation fail, even though the action does not access that path. It also makes setup time and transfer size depend on the size of the whole repository. In the observed workflow, downloading and staging the repository added approximately 10 seconds before the action failed.

The dangling-symbolic-link failure is related to #3234. This report additionally covers its interaction with the new $/ syntax: loading a small self-repository action exposes it to every unrelated file in the repository and incurs the cost of staging the complete repository.

Feature announcement:
https://github.blog/changelog/2026-07-30-reference-same-repository-actions-with-self-repository-syntax/

To Reproduce

  1. Add a minimal composite action at .github/actions/example/action.yml:

    name: Example
    runs:
      using: composite
      steps:
        - shell: bash
          run: echo "Example action"
  2. Add and commit a dangling symbolic link outside the action directory:

    mkdir -p unrelated/vendor
    ln -s ../missing/header.h unrelated/vendor/header.h
    git add unrelated/vendor/header.h
    git commit -m "Add reproduction"
  3. Reference the action before checkout:

    jobs:
      reproduce:
        runs-on: ubuntu-24.04
        steps:
          - uses: $/.github/actions/example
  4. Run the workflow.

  5. Observe that the job fails while preparing actions, before the composite action executes.

Expected behavior

The runner should load the referenced action without staging unrelated repository contents. A dangling symbolic link outside .github/actions/example should not prevent that action from running.

Ideally, setup time and transfer size should be proportional to the referenced action and its declared dependencies, not to the size of the complete repository. If staging the whole repository remains necessary, dangling symbolic links should at least be preserved without requiring their targets to exist.

Runner Version and Platform

  • Runner version: 2.336.0
  • Platform: GitHub-hosted Linux runner
  • Operating system: Ubuntu 24.04.4 LTS
  • Runner image: ubuntu-24.04, version 20260720.247.2

What's not working?

The failure occurs during action download and staging, before any workflow step runs. A normal Git checkout on Linux can preserve the dangling symbolic link, but preparing the self-repository action fails while processing the unrelated path.

This also creates a performance cost for every $/ action because the complete repository is staged before the action executes. If the self-repository action subsequently performs a checkout, the repository transfer is duplicated.

Job Log Output

Sanitized example:

Download action repository 'owner/repository@<sha>'
Error: Could not find file '.../_staging/repository-<sha>/unrelated/vendor/header.h'.

Approximately 10 seconds were spent downloading and staging the repository (large monorepo) before this error was reported.

Runner and Worker's Diagnostic Logs

The failure was observed on a GitHub-hosted runner, so _diag logs are not available.

Suggested approach

Download and cache an archive scoped to the referenced action path instead of staging the complete repository. For example:

- uses: $/.github/actions/example

would initially make only .github/actions/example/** available.

This would:

  • Isolate action preparation from unrelated repository contents.
  • Avoid failures caused by dangling links outside the action directory.
  • Reduce network transfer and disk use for large repositories.
  • Avoid unnecessary duplicate transfer for actions that perform checkout.
  • Permit caching by repository, commit, and action path.

Nested $/ action references could be resolved independently. An action that requires files outside its directory could declare additional paths explicitly in its metadata.

Azure Pipelines comparison

Azure Pipelines uses a different task-distribution model, but its approach may be useful here. Custom tasks are packaged independently, and the agent downloads and caches a task-specific ZIP using the task ID and version. Preparing a task does not require staging unrelated contents from the source repository.

GitHub could apply the same principle to self-repository actions while retaining commit-pinned $/ references: download the smallest artifact needed to run the selected action.

References:

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions