Skip to content

fix(processing): Close temp tarball before reading it - #6319

Open
jam-jee wants to merge 1 commit into
aws:masterfrom
jam-jee:fix/windows-line-endings
Open

jam-jee wants to merge 1 commit into
aws:masterfrom
jam-jee:fix/windows-line-endings

Conversation

@jam-jee

@jam-jee jam-jee commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

FrameworkProcessor._package_code read and then deleted its temporary tar.gz while the NamedTemporaryFile handle was still open. On Windows that raises PermissionError: [WinError 32] because the open handle still holds the file, so every FrameworkProcessor.run() on Windows failed before the job was submitted.

The fix closes the handle first, reads the archive through a with open(...) context, and unlinks it in a finally block so the temp file is removed on every path (including upload failure). Behaviour on Linux/macOS is unchanged.

The LF line-ending fixes for sm_train.sh and the repack launcher that were originally bundled with this change are already covered by open PRs #6255 / #6088 (sm_train.sh) and #6313 (repack launcher), so they are deliberately not repeated here.

Issues fixed

Fixes #5873

Testing

New unit test in sagemaker-core/tests/unit/test_processing.py: test_package_code_closes_temp_handle_before_unlink -- fails on master, passes with this change.

tests/unit/test_processing.py: 124 passed. black -l 100 and flake8 clean on changed files.

Integration tests

None added. The defect is a Windows file lock on an open temp handle; CI runs Linux, where the old code also passed, so an integ test could not reproduce it. The unit test is the regression proof, and the tarball round-trip itself is exercised end-to-end by the FrameworkProcessor integ test added in #6318.


X-AI-Prompt: Fix S-effort PySDK V3 bugs, windows theme
X-AI-Tool: Kiro

FrameworkProcessor._package_code read and deleted its temporary tar.gz
while the NamedTemporaryFile handle was still open. On Windows that
raises PermissionError (WinError 32) because the file is still held by
the open handle. Close the handle first, read the archive in a with-open
context, and unlink it in a finally block so the temp file is removed
on every path.

The LF line-ending fixes for sm_train.sh and the repack launcher that
originally shared this branch are covered by open PRs aws#6255 / aws#6088
(sm_train.sh) and aws#6313 (repack launcher), so they are not repeated here.

Fixes aws#5873

---
X-AI-Prompt: Fix S-effort PySDK V3 bugs, windows theme
X-AI-Tool: Kiro
@jam-jee
jam-jee deployed to auto-approve September 24, 2026 21:36 — with GitHub Actions Active
@jam-jee
jam-jee deployed to auto-approve September 24, 2026 21:36 — with GitHub Actions Active
@jam-jee
jam-jee deployed to auto-approve September 24, 2026 21:36 — with GitHub Actions Active
@github-actions

github-actions Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Claude finished @jam-jee's task in 47s —— View job


PR Review: Close temp tarball before reading it

  • Read the diff and changed files
  • Analyze correctness, best practices, security, performance, tests

Verdict

This is a clean, correct bug fix. It properly addresses the Windows PermissionError: [WinError 32] in FrameworkProcessor._package_code and, as a bonus, fixes a pre-existing file-handle leak. I recommend merging.

What the fix does well

  1. Root-cause fix (processing.py:1292-1293). Creating the NamedTemporaryFile with delete=False and immediately tmp.close()-ing it means no handle is held while tarfile.open(tmp.name, ...) reopens the path — the exact scenario that fails on Windows.

  2. Fixes a latent handle leak (processing.py:1316-1317). The old code did body=open(tmp.name, "rb").read(), which never closed the read handle. Wrapping it in with open(...) as tar_file: closes it deterministically. Good catch.

  3. More robust cleanup (processing.py:1327-1328). Moving os.unlink(tmp.name) into a finally block ensures the temp file is removed on every path — including when the tar build or S3 upload raises. Previously an upload failure would leak the temp file. tmp.name always exists once NamedTemporaryFile returns, so the unconditional unlink in finally is safe.

Test

test_package_code_closes_temp_handle_before_unlink targets the exact regression: it tracks every open .tar.gz handle and asserts none remain open at os.unlink time. This is a meaningful behavioral assertion rather than a smoke test, and it reproduces the reported failure on master. Nicely scoped.

Minor / non-blocking observations

  • The whole archive is still read into memory via .read() before upload. That's unchanged from before (not a regression), but for very large source_dir/dependency bundles it could be worth streaming in a future change — out of scope here.
  • The test's patch("builtins.open", ...) is global for the duration of the call; it correctly filters to .tar.gz paths so unrelated opens (tarfile internals, etc.) aren't affected. Fine as-is.

No correctness, security, or backward-compatibility concerns. Behavior on Linux/macOS is unchanged.

Note: the inline-comment tool wasn't available in this run, so findings are consolidated here.
• branch fix/windows-line-endings

This branch was successfully deployed

1 active deployment
auto-approve — 28c7c901 Deployed Sep 24, 2026 by jam-jee via wait-for-approval #1803
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FrameworkProcessor._package_code fails on Windows with PermissionError (WinError 32) when deleting temp tar.gz

1 participant