Skip to content

ContainerCodeExecutor drops output files that are hard links #7906

Open

Description

@AkshayShah03

Describe the bug

ContainerCodeExecutor (input/output files added in effd641) returns only the first name when the executed code leaves two hard-linked names in the output directory, for example after os.link("a.csv", "b.csv") or cp -l. The second file is silently missing from CodeExecutionResult.output_files.

Docker's get_archive writes the second path to an inode it has already archived as a hard-link entry (type LNK, size 0), as Python's tarfile.add does. _extract_output_files keeps only entries where member.isfile() is true, and that is false for link entries.

src/google/adk/code_executors/container_code_executor.py, in _extract_output_files:

for member in tar.getmembers():
  if member.isfile():

To Reproduce

The repro builds the archive from a real directory with tarfile, as Docker would return it, and feeds it to the executor through a mocked container, the same way tests/unittests/code_executors/test_container_code_executor.py does.

archive members: [('outputs', 'DIR'), ('outputs/a.csv', 'REG'), ('outputs/b.csv', 'LNK')]
output_files: ['a.csv']        # expected ['a.csv', 'b.csv']

Expected behavior

Both names are returned with the same content.

Suggested fix

if member.isfile() or member.islnk():

tar.extractfile() already resolves a hard-link member to its target's data inside the archive, so no other change is needed. Plus a regression test that builds the archive from a directory containing a hard link.

Question (separate, smaller)

CodeExecutorContext.add_input_files() only appends. If code adds data.csv in one turn and an updated data.csv in a later turn, every later execution fails with ValueError: Duplicate input file name: 'data.csv', and since the list lives in session state the session can't recover. The flow's own inline-file path avoids this by skipping known names. Should add_input_files replace an existing file with the same name, or is the error intended?

I can open a PR for the hard-link fix if that's welcome.

Desktop (please complete the following information):

  • OS: macOS
  • Python version: 3.12
  • ADK version: main (8cd3b12, 2.13.0)

Activity

  1. OKAN-SOFTWARE commented on Oct 31, 2026

    @OKAN-SOFTWARE

    I've reproduced the hard-link issue and tested a minimal fix that accepts TarInfo.islnk() alongside regular files.

    I added a regression test using a mocked Docker archive that verifies both hard-linked filenames retain their content and symbolic links remain excluded.

    Validation: 41 passed, 6 skipped (Windows-specific skips). Ruff, isort, Pyink, and whitespace checks passed.

    I noticed you offered to open a PR. Are you planning to work on it? If so, I don't want to duplicate your effort. Otherwise, I'd be happy to contribute the tested fix.

    Image
  2. AkshayShah03 commented on Nov 1, 2026

    @AkshayShah03
    ContributorAuthor

    Thanks for picking it up — go ahead and open the PR. I'm focusing on #7905, so happy to review yours when it's up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions