fix(serve): create local model_path dir before using it as download dir - #6147

Merged
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder
Aug 3, 2026
Merged

fix(serve): create local model_path dir before using it as download dir#6147
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder

Conversation

@lucasjia-aws

Copy link
Copy Markdown
Collaborator

ModelBuilder.build() assigned the default model_path (/tmp/sagemaker/model-builder/) to settings._local_download_dir without creating it on disk, so repack_model()'s _tmpdir() validation raised "Inputted directory ... does not exist" for source_code repack builds. Only use model_path as the local download dir when it is a local path, creating it first; skip s3:// URIs.

Issue #, if available:

Description of changes:

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

ModelBuilder.build() assigned the default model_path
(/tmp/sagemaker/model-builder/<uuid>) to settings._local_download_dir
without creating it on disk, so repack_model()'s _tmpdir() validation
raised "Inputted directory ... does not exist" for source_code repack
builds. Only use model_path as the local download dir when it is a
local path, creating it first; skip s3:// URIs.
@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 50s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff
  • Review the change for correctness, best practices, security, tests

The fix looks correct and well-targeted. ModelBuilder's default model_path is a local dir (/tmp/sagemaker/model-builder/<uuid>) created lazily, and repack_model()'s _tmpdir() validation requires it to exist on disk — so creating it before wiring it into settings._local_download_dir resolves the "Inputted directory ... does not exist" error.

A few things I verified:

  • os is already imported (model_builder.py:22), so os.makedirs is safe.
  • ✅ The isinstance(self.model_path, str) guard correctly avoids the case where model_path could be non-string, and not startswith("s3://") correctly skips remote artifacts. This is consistent with the existing self.model_path.startswith("s3://") checks elsewhere in the file (lines 1883, 1918).
  • os.makedirs(..., exist_ok=True) is idempotent, so re-running build() won't raise.

Minor considerations (non-blocking)

  1. Behavior change for s3:// paths: Previously _local_download_dir was set unconditionally to self.model_path (even when it was an s3:// URI, e.g. from a TrainingJob/ModelTrainer). Now it's left unset for s3:// paths. This is almost certainly the right behavior (a local download dir should never be an S3 URI), but it is a subtle behavior change — worth confirming no downstream code relied on _local_download_dir holding the S3 URI.

  2. file:// prefix: The guard treats file://... paths as local and would call os.makedirs("file://..."), creating a literal file:/ directory. Looking at the code, model_path is stored as a plain path and file:// is only prepended when building s3_upload_path (line 1788), so this shouldn't occur in practice — just flagging it as a latent edge case if a user ever passes a file://model_path.

  3. Tests: No test accompanies this change. A small unit test asserting that (a) a local model_path is created on disk and assigned to settings._local_download_dir, and (b) an s3://model_path leaves it unset, would guard against regressions of exactly the bug this fixes.

Overall this is a small, sensible bug fix. The main suggestion is adding a regression test for the source_code repack path.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

1. s3:// behavior change — Intentional and safe. settings.local_download_dir is only ever consumed as the parent dir for tempfile.mkdtemp() in repack_model() and fw_utils — nothing reads it as an S3 URI. The previous unconditional assignment was actually buggy for an S3 model_path (e.g. from a TrainingJob/ModelTrainer): _tmpdir() would call os.path.exists("s3://...") and raise the same ValueError. Leaving it unset for S3 paths falls back to the system temp dir, which is the correct behavior.

2. file:// prefix — Not reachable in practice. model_path is always stored as a plain filesystem path; file:// is only prepended when constructing s3_upload_path, so os.makedirs("file://...") can't occur here. Agreed it's a latent edge case, but out of scope for this fix.

3. Regression test — Added TestModelBuilderLocalDownloadDir in test_model_builder_core.py covering both branches: a local model_path is created on disk and wired into settings.local_download_dir, and an s3://model_path leaves it unset.

@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 46s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff (/tmp/pr.diff)
  • Review the fix for correctness against repack_model/fw_utils consumers
  • Review the added regression tests

The updated PR looks clean and correct. The added tests address the one gap flagged in the earlier round.

Correctness — confirmed

  • The guard isinstance(self.model_path, str) and not self.model_path.startswith("s3://") correctly scopes _local_download_dir to real local paths, and os.makedirs(..., exist_ok=True) satisfies the os.path.exists(...) and os.path.isdir(...) check in fw_utils._tmpdir/repack_model (sagemaker-core/src/sagemaker/core/fw_utils.py:450-463).
  • The behavior change for s3:// paths is the right call and, as the author noted, actually fixes a latent bug: previously an S3 model_path (from TrainingJob/ModelTrainer, e.g. model_builder.py:3064,3072) would be assigned verbatim and then trip the same ValueError in _tmpdir. Both consumers (fw_utils.py:462, common_utils.py:595-601) only use it as the dir= parent for tempfile.mkdtemp, so leaving it unset falls back to the system temp dir — no code reads it as an S3 URI. ✅
  • exist_ok=True keeps build() idempotent on re-run. ✅

Tests — good coverage

  • test_local_model_path_is_created_and_used and test_s3_model_path_leaves_local_download_dir_unset cover both branches directly, using a real SessionSettings() so the local_download_dir property (not just the mock attribute) is exercised. This is exactly the regression guard the source_code repack path needed. ✅

Minor (non-blocking)

  • The file:// edge case is still theoretically present but, as discussed, unreachable — model_path is only ever a plain filesystem path and file:// is prepended solely for s3_upload_path. Fine to leave out of scope.

No blocking issues. Ship it.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

Both test failures are flaky and unrelated to this PR (which only touches sagemaker-serve/model_builder.py):

  • mlopstest_feature_processor_transform_online_only_store_ingestion — a ConcurrentModificationException in the shaded AWS SDK AttributeMap when the Feature Store Spark connector builds its client concurrently across executor threads.
  • us-east-1test_inspect_ai_upload_benchmarks — the pipeline execution failed server-side with Pipeline ... has been modified since your last read (a concurrent-modification conflict under parallel test runs).

Both are concurrency races in infra/service code, not regressions from this change. Retrying should turn them green.

@lucasjia-aws
lucasjia-aws merged commit 748910e into aws:masterAug 3, 2026
16 of 21 checks passed
@github-actionsgithub-actionsBot mentioned this pull request Aug 10, 2026
Sign up for freeto 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.

2 participants

@lucasjia-aws@mujtaba1747
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(serve): create local model_path dir before using it as download dir - #6147

Merged
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder
Aug 3, 2026
Merged

fix(serve): create local model_path dir before using it as download dir#6147
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder

Conversation

@lucasjia-aws

Copy link
Copy Markdown
Collaborator

ModelBuilder.build() assigned the default model_path (/tmp/sagemaker/model-builder/) to settings._local_download_dir without creating it on disk, so repack_model()'s _tmpdir() validation raised "Inputted directory ... does not exist" for source_code repack builds. Only use model_path as the local download dir when it is a local path, creating it first; skip s3:// URIs.

Issue #, if available:

Description of changes:

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

ModelBuilder.build() assigned the default model_path
(/tmp/sagemaker/model-builder/<uuid>) to settings._local_download_dir
without creating it on disk, so repack_model()'s _tmpdir() validation
raised "Inputted directory ... does not exist" for source_code repack
builds. Only use model_path as the local download dir when it is a
local path, creating it first; skip s3:// URIs.
@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 50s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff
  • Review the change for correctness, best practices, security, tests

The fix looks correct and well-targeted. ModelBuilder's default model_path is a local dir (/tmp/sagemaker/model-builder/<uuid>) created lazily, and repack_model()'s _tmpdir() validation requires it to exist on disk — so creating it before wiring it into settings._local_download_dir resolves the "Inputted directory ... does not exist" error.

A few things I verified:

  • os is already imported (model_builder.py:22), so os.makedirs is safe.
  • ✅ The isinstance(self.model_path, str) guard correctly avoids the case where model_path could be non-string, and not startswith("s3://") correctly skips remote artifacts. This is consistent with the existing self.model_path.startswith("s3://") checks elsewhere in the file (lines 1883, 1918).
  • os.makedirs(..., exist_ok=True) is idempotent, so re-running build() won't raise.

Minor considerations (non-blocking)

  1. Behavior change for s3:// paths: Previously _local_download_dir was set unconditionally to self.model_path (even when it was an s3:// URI, e.g. from a TrainingJob/ModelTrainer). Now it's left unset for s3:// paths. This is almost certainly the right behavior (a local download dir should never be an S3 URI), but it is a subtle behavior change — worth confirming no downstream code relied on _local_download_dir holding the S3 URI.

  2. file:// prefix: The guard treats file://... paths as local and would call os.makedirs("file://..."), creating a literal file:/ directory. Looking at the code, model_path is stored as a plain path and file:// is only prepended when building s3_upload_path (line 1788), so this shouldn't occur in practice — just flagging it as a latent edge case if a user ever passes a file://model_path.

  3. Tests: No test accompanies this change. A small unit test asserting that (a) a local model_path is created on disk and assigned to settings._local_download_dir, and (b) an s3://model_path leaves it unset, would guard against regressions of exactly the bug this fixes.

Overall this is a small, sensible bug fix. The main suggestion is adding a regression test for the source_code repack path.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

1. s3:// behavior change — Intentional and safe. settings.local_download_dir is only ever consumed as the parent dir for tempfile.mkdtemp() in repack_model() and fw_utils — nothing reads it as an S3 URI. The previous unconditional assignment was actually buggy for an S3 model_path (e.g. from a TrainingJob/ModelTrainer): _tmpdir() would call os.path.exists("s3://...") and raise the same ValueError. Leaving it unset for S3 paths falls back to the system temp dir, which is the correct behavior.

2. file:// prefix — Not reachable in practice. model_path is always stored as a plain filesystem path; file:// is only prepended when constructing s3_upload_path, so os.makedirs("file://...") can't occur here. Agreed it's a latent edge case, but out of scope for this fix.

3. Regression test — Added TestModelBuilderLocalDownloadDir in test_model_builder_core.py covering both branches: a local model_path is created on disk and wired into settings.local_download_dir, and an s3://model_path leaves it unset.

@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 46s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff (/tmp/pr.diff)
  • Review the fix for correctness against repack_model/fw_utils consumers
  • Review the added regression tests

The updated PR looks clean and correct. The added tests address the one gap flagged in the earlier round.

Correctness — confirmed

  • The guard isinstance(self.model_path, str) and not self.model_path.startswith("s3://") correctly scopes _local_download_dir to real local paths, and os.makedirs(..., exist_ok=True) satisfies the os.path.exists(...) and os.path.isdir(...) check in fw_utils._tmpdir/repack_model (sagemaker-core/src/sagemaker/core/fw_utils.py:450-463).
  • The behavior change for s3:// paths is the right call and, as the author noted, actually fixes a latent bug: previously an S3 model_path (from TrainingJob/ModelTrainer, e.g. model_builder.py:3064,3072) would be assigned verbatim and then trip the same ValueError in _tmpdir. Both consumers (fw_utils.py:462, common_utils.py:595-601) only use it as the dir= parent for tempfile.mkdtemp, so leaving it unset falls back to the system temp dir — no code reads it as an S3 URI. ✅
  • exist_ok=True keeps build() idempotent on re-run. ✅

Tests — good coverage

  • test_local_model_path_is_created_and_used and test_s3_model_path_leaves_local_download_dir_unset cover both branches directly, using a real SessionSettings() so the local_download_dir property (not just the mock attribute) is exercised. This is exactly the regression guard the source_code repack path needed. ✅

Minor (non-blocking)

  • The file:// edge case is still theoretically present but, as discussed, unreachable — model_path is only ever a plain filesystem path and file:// is prepended solely for s3_upload_path. Fine to leave out of scope.

No blocking issues. Ship it.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

Both test failures are flaky and unrelated to this PR (which only touches sagemaker-serve/model_builder.py):

  • mlopstest_feature_processor_transform_online_only_store_ingestion — a ConcurrentModificationException in the shaded AWS SDK AttributeMap when the Feature Store Spark connector builds its client concurrently across executor threads.
  • us-east-1test_inspect_ai_upload_benchmarks — the pipeline execution failed server-side with Pipeline ... has been modified since your last read (a concurrent-modification conflict under parallel test runs).

Both are concurrency races in infra/service code, not regressions from this change. Retrying should turn them green.

@lucasjia-aws
lucasjia-aws merged commit 748910e into aws:masterAug 3, 2026
16 of 21 checks passed
@github-actionsgithub-actionsBot mentioned this pull request Aug 10, 2026
Sign up for freeto 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.

2 participants

@lucasjia-aws@mujtaba1747
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(serve): create local model_path dir before using it as download dir - #6147

Merged
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder
Aug 3, 2026
Merged

fix(serve): create local model_path dir before using it as download dir#6147
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder

Conversation

@lucasjia-aws

Copy link
Copy Markdown
Collaborator

ModelBuilder.build() assigned the default model_path (/tmp/sagemaker/model-builder/) to settings._local_download_dir without creating it on disk, so repack_model()'s _tmpdir() validation raised "Inputted directory ... does not exist" for source_code repack builds. Only use model_path as the local download dir when it is a local path, creating it first; skip s3:// URIs.

Issue #, if available:

Description of changes:

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

ModelBuilder.build() assigned the default model_path
(/tmp/sagemaker/model-builder/<uuid>) to settings._local_download_dir
without creating it on disk, so repack_model()'s _tmpdir() validation
raised "Inputted directory ... does not exist" for source_code repack
builds. Only use model_path as the local download dir when it is a
local path, creating it first; skip s3:// URIs.
@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 50s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff
  • Review the change for correctness, best practices, security, tests

The fix looks correct and well-targeted. ModelBuilder's default model_path is a local dir (/tmp/sagemaker/model-builder/<uuid>) created lazily, and repack_model()'s _tmpdir() validation requires it to exist on disk — so creating it before wiring it into settings._local_download_dir resolves the "Inputted directory ... does not exist" error.

A few things I verified:

  • os is already imported (model_builder.py:22), so os.makedirs is safe.
  • ✅ The isinstance(self.model_path, str) guard correctly avoids the case where model_path could be non-string, and not startswith("s3://") correctly skips remote artifacts. This is consistent with the existing self.model_path.startswith("s3://") checks elsewhere in the file (lines 1883, 1918).
  • os.makedirs(..., exist_ok=True) is idempotent, so re-running build() won't raise.

Minor considerations (non-blocking)

  1. Behavior change for s3:// paths: Previously _local_download_dir was set unconditionally to self.model_path (even when it was an s3:// URI, e.g. from a TrainingJob/ModelTrainer). Now it's left unset for s3:// paths. This is almost certainly the right behavior (a local download dir should never be an S3 URI), but it is a subtle behavior change — worth confirming no downstream code relied on _local_download_dir holding the S3 URI.

  2. file:// prefix: The guard treats file://... paths as local and would call os.makedirs("file://..."), creating a literal file:/ directory. Looking at the code, model_path is stored as a plain path and file:// is only prepended when building s3_upload_path (line 1788), so this shouldn't occur in practice — just flagging it as a latent edge case if a user ever passes a file://model_path.

  3. Tests: No test accompanies this change. A small unit test asserting that (a) a local model_path is created on disk and assigned to settings._local_download_dir, and (b) an s3://model_path leaves it unset, would guard against regressions of exactly the bug this fixes.

Overall this is a small, sensible bug fix. The main suggestion is adding a regression test for the source_code repack path.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

1. s3:// behavior change — Intentional and safe. settings.local_download_dir is only ever consumed as the parent dir for tempfile.mkdtemp() in repack_model() and fw_utils — nothing reads it as an S3 URI. The previous unconditional assignment was actually buggy for an S3 model_path (e.g. from a TrainingJob/ModelTrainer): _tmpdir() would call os.path.exists("s3://...") and raise the same ValueError. Leaving it unset for S3 paths falls back to the system temp dir, which is the correct behavior.

2. file:// prefix — Not reachable in practice. model_path is always stored as a plain filesystem path; file:// is only prepended when constructing s3_upload_path, so os.makedirs("file://...") can't occur here. Agreed it's a latent edge case, but out of scope for this fix.

3. Regression test — Added TestModelBuilderLocalDownloadDir in test_model_builder_core.py covering both branches: a local model_path is created on disk and wired into settings.local_download_dir, and an s3://model_path leaves it unset.

@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 46s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff (/tmp/pr.diff)
  • Review the fix for correctness against repack_model/fw_utils consumers
  • Review the added regression tests

The updated PR looks clean and correct. The added tests address the one gap flagged in the earlier round.

Correctness — confirmed

  • The guard isinstance(self.model_path, str) and not self.model_path.startswith("s3://") correctly scopes _local_download_dir to real local paths, and os.makedirs(..., exist_ok=True) satisfies the os.path.exists(...) and os.path.isdir(...) check in fw_utils._tmpdir/repack_model (sagemaker-core/src/sagemaker/core/fw_utils.py:450-463).
  • The behavior change for s3:// paths is the right call and, as the author noted, actually fixes a latent bug: previously an S3 model_path (from TrainingJob/ModelTrainer, e.g. model_builder.py:3064,3072) would be assigned verbatim and then trip the same ValueError in _tmpdir. Both consumers (fw_utils.py:462, common_utils.py:595-601) only use it as the dir= parent for tempfile.mkdtemp, so leaving it unset falls back to the system temp dir — no code reads it as an S3 URI. ✅
  • exist_ok=True keeps build() idempotent on re-run. ✅

Tests — good coverage

  • test_local_model_path_is_created_and_used and test_s3_model_path_leaves_local_download_dir_unset cover both branches directly, using a real SessionSettings() so the local_download_dir property (not just the mock attribute) is exercised. This is exactly the regression guard the source_code repack path needed. ✅

Minor (non-blocking)

  • The file:// edge case is still theoretically present but, as discussed, unreachable — model_path is only ever a plain filesystem path and file:// is prepended solely for s3_upload_path. Fine to leave out of scope.

No blocking issues. Ship it.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

Both test failures are flaky and unrelated to this PR (which only touches sagemaker-serve/model_builder.py):

  • mlopstest_feature_processor_transform_online_only_store_ingestion — a ConcurrentModificationException in the shaded AWS SDK AttributeMap when the Feature Store Spark connector builds its client concurrently across executor threads.
  • us-east-1test_inspect_ai_upload_benchmarks — the pipeline execution failed server-side with Pipeline ... has been modified since your last read (a concurrent-modification conflict under parallel test runs).

Both are concurrency races in infra/service code, not regressions from this change. Retrying should turn them green.

@lucasjia-aws
lucasjia-aws merged commit 748910e into aws:masterAug 3, 2026
16 of 21 checks passed
@github-actionsgithub-actionsBot mentioned this pull request Aug 10, 2026
Sign up for freeto 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.

2 participants

@lucasjia-aws@mujtaba1747
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(serve): create local model_path dir before using it as download dir - #6147

Merged
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder
Aug 3, 2026
Merged

fix(serve): create local model_path dir before using it as download dir#6147
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder

Conversation

@lucasjia-aws

Copy link
Copy Markdown
Collaborator

ModelBuilder.build() assigned the default model_path (/tmp/sagemaker/model-builder/) to settings._local_download_dir without creating it on disk, so repack_model()'s _tmpdir() validation raised "Inputted directory ... does not exist" for source_code repack builds. Only use model_path as the local download dir when it is a local path, creating it first; skip s3:// URIs.

Issue #, if available:

Description of changes:

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

ModelBuilder.build() assigned the default model_path
(/tmp/sagemaker/model-builder/<uuid>) to settings._local_download_dir
without creating it on disk, so repack_model()'s _tmpdir() validation
raised "Inputted directory ... does not exist" for source_code repack
builds. Only use model_path as the local download dir when it is a
local path, creating it first; skip s3:// URIs.
@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 50s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff
  • Review the change for correctness, best practices, security, tests

The fix looks correct and well-targeted. ModelBuilder's default model_path is a local dir (/tmp/sagemaker/model-builder/<uuid>) created lazily, and repack_model()'s _tmpdir() validation requires it to exist on disk — so creating it before wiring it into settings._local_download_dir resolves the "Inputted directory ... does not exist" error.

A few things I verified:

  • os is already imported (model_builder.py:22), so os.makedirs is safe.
  • ✅ The isinstance(self.model_path, str) guard correctly avoids the case where model_path could be non-string, and not startswith("s3://") correctly skips remote artifacts. This is consistent with the existing self.model_path.startswith("s3://") checks elsewhere in the file (lines 1883, 1918).
  • os.makedirs(..., exist_ok=True) is idempotent, so re-running build() won't raise.

Minor considerations (non-blocking)

  1. Behavior change for s3:// paths: Previously _local_download_dir was set unconditionally to self.model_path (even when it was an s3:// URI, e.g. from a TrainingJob/ModelTrainer). Now it's left unset for s3:// paths. This is almost certainly the right behavior (a local download dir should never be an S3 URI), but it is a subtle behavior change — worth confirming no downstream code relied on _local_download_dir holding the S3 URI.

  2. file:// prefix: The guard treats file://... paths as local and would call os.makedirs("file://..."), creating a literal file:/ directory. Looking at the code, model_path is stored as a plain path and file:// is only prepended when building s3_upload_path (line 1788), so this shouldn't occur in practice — just flagging it as a latent edge case if a user ever passes a file://model_path.

  3. Tests: No test accompanies this change. A small unit test asserting that (a) a local model_path is created on disk and assigned to settings._local_download_dir, and (b) an s3://model_path leaves it unset, would guard against regressions of exactly the bug this fixes.

Overall this is a small, sensible bug fix. The main suggestion is adding a regression test for the source_code repack path.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

1. s3:// behavior change — Intentional and safe. settings.local_download_dir is only ever consumed as the parent dir for tempfile.mkdtemp() in repack_model() and fw_utils — nothing reads it as an S3 URI. The previous unconditional assignment was actually buggy for an S3 model_path (e.g. from a TrainingJob/ModelTrainer): _tmpdir() would call os.path.exists("s3://...") and raise the same ValueError. Leaving it unset for S3 paths falls back to the system temp dir, which is the correct behavior.

2. file:// prefix — Not reachable in practice. model_path is always stored as a plain filesystem path; file:// is only prepended when constructing s3_upload_path, so os.makedirs("file://...") can't occur here. Agreed it's a latent edge case, but out of scope for this fix.

3. Regression test — Added TestModelBuilderLocalDownloadDir in test_model_builder_core.py covering both branches: a local model_path is created on disk and wired into settings.local_download_dir, and an s3://model_path leaves it unset.

@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 46s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff (/tmp/pr.diff)
  • Review the fix for correctness against repack_model/fw_utils consumers
  • Review the added regression tests

The updated PR looks clean and correct. The added tests address the one gap flagged in the earlier round.

Correctness — confirmed

  • The guard isinstance(self.model_path, str) and not self.model_path.startswith("s3://") correctly scopes _local_download_dir to real local paths, and os.makedirs(..., exist_ok=True) satisfies the os.path.exists(...) and os.path.isdir(...) check in fw_utils._tmpdir/repack_model (sagemaker-core/src/sagemaker/core/fw_utils.py:450-463).
  • The behavior change for s3:// paths is the right call and, as the author noted, actually fixes a latent bug: previously an S3 model_path (from TrainingJob/ModelTrainer, e.g. model_builder.py:3064,3072) would be assigned verbatim and then trip the same ValueError in _tmpdir. Both consumers (fw_utils.py:462, common_utils.py:595-601) only use it as the dir= parent for tempfile.mkdtemp, so leaving it unset falls back to the system temp dir — no code reads it as an S3 URI. ✅
  • exist_ok=True keeps build() idempotent on re-run. ✅

Tests — good coverage

  • test_local_model_path_is_created_and_used and test_s3_model_path_leaves_local_download_dir_unset cover both branches directly, using a real SessionSettings() so the local_download_dir property (not just the mock attribute) is exercised. This is exactly the regression guard the source_code repack path needed. ✅

Minor (non-blocking)

  • The file:// edge case is still theoretically present but, as discussed, unreachable — model_path is only ever a plain filesystem path and file:// is prepended solely for s3_upload_path. Fine to leave out of scope.

No blocking issues. Ship it.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

Both test failures are flaky and unrelated to this PR (which only touches sagemaker-serve/model_builder.py):

  • mlopstest_feature_processor_transform_online_only_store_ingestion — a ConcurrentModificationException in the shaded AWS SDK AttributeMap when the Feature Store Spark connector builds its client concurrently across executor threads.
  • us-east-1test_inspect_ai_upload_benchmarks — the pipeline execution failed server-side with Pipeline ... has been modified since your last read (a concurrent-modification conflict under parallel test runs).

Both are concurrency races in infra/service code, not regressions from this change. Retrying should turn them green.

@lucasjia-aws
lucasjia-aws merged commit 748910e into aws:masterAug 3, 2026
16 of 21 checks passed
@github-actionsgithub-actionsBot mentioned this pull request Aug 10, 2026
Sign up for freeto 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.

2 participants

@lucasjia-aws@mujtaba1747
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(serve): create local model_path dir before using it as download dir - #6147

Merged
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder
Aug 3, 2026
Merged

fix(serve): create local model_path dir before using it as download dir#6147
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder

Conversation

@lucasjia-aws

Copy link
Copy Markdown
Collaborator

ModelBuilder.build() assigned the default model_path (/tmp/sagemaker/model-builder/) to settings._local_download_dir without creating it on disk, so repack_model()'s _tmpdir() validation raised "Inputted directory ... does not exist" for source_code repack builds. Only use model_path as the local download dir when it is a local path, creating it first; skip s3:// URIs.

Issue #, if available:

Description of changes:

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

ModelBuilder.build() assigned the default model_path
(/tmp/sagemaker/model-builder/<uuid>) to settings._local_download_dir
without creating it on disk, so repack_model()'s _tmpdir() validation
raised "Inputted directory ... does not exist" for source_code repack
builds. Only use model_path as the local download dir when it is a
local path, creating it first; skip s3:// URIs.
@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 50s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff
  • Review the change for correctness, best practices, security, tests

The fix looks correct and well-targeted. ModelBuilder's default model_path is a local dir (/tmp/sagemaker/model-builder/<uuid>) created lazily, and repack_model()'s _tmpdir() validation requires it to exist on disk — so creating it before wiring it into settings._local_download_dir resolves the "Inputted directory ... does not exist" error.

A few things I verified:

  • os is already imported (model_builder.py:22), so os.makedirs is safe.
  • ✅ The isinstance(self.model_path, str) guard correctly avoids the case where model_path could be non-string, and not startswith("s3://") correctly skips remote artifacts. This is consistent with the existing self.model_path.startswith("s3://") checks elsewhere in the file (lines 1883, 1918).
  • os.makedirs(..., exist_ok=True) is idempotent, so re-running build() won't raise.

Minor considerations (non-blocking)

  1. Behavior change for s3:// paths: Previously _local_download_dir was set unconditionally to self.model_path (even when it was an s3:// URI, e.g. from a TrainingJob/ModelTrainer). Now it's left unset for s3:// paths. This is almost certainly the right behavior (a local download dir should never be an S3 URI), but it is a subtle behavior change — worth confirming no downstream code relied on _local_download_dir holding the S3 URI.

  2. file:// prefix: The guard treats file://... paths as local and would call os.makedirs("file://..."), creating a literal file:/ directory. Looking at the code, model_path is stored as a plain path and file:// is only prepended when building s3_upload_path (line 1788), so this shouldn't occur in practice — just flagging it as a latent edge case if a user ever passes a file://model_path.

  3. Tests: No test accompanies this change. A small unit test asserting that (a) a local model_path is created on disk and assigned to settings._local_download_dir, and (b) an s3://model_path leaves it unset, would guard against regressions of exactly the bug this fixes.

Overall this is a small, sensible bug fix. The main suggestion is adding a regression test for the source_code repack path.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

1. s3:// behavior change — Intentional and safe. settings.local_download_dir is only ever consumed as the parent dir for tempfile.mkdtemp() in repack_model() and fw_utils — nothing reads it as an S3 URI. The previous unconditional assignment was actually buggy for an S3 model_path (e.g. from a TrainingJob/ModelTrainer): _tmpdir() would call os.path.exists("s3://...") and raise the same ValueError. Leaving it unset for S3 paths falls back to the system temp dir, which is the correct behavior.

2. file:// prefix — Not reachable in practice. model_path is always stored as a plain filesystem path; file:// is only prepended when constructing s3_upload_path, so os.makedirs("file://...") can't occur here. Agreed it's a latent edge case, but out of scope for this fix.

3. Regression test — Added TestModelBuilderLocalDownloadDir in test_model_builder_core.py covering both branches: a local model_path is created on disk and wired into settings.local_download_dir, and an s3://model_path leaves it unset.

@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 46s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff (/tmp/pr.diff)
  • Review the fix for correctness against repack_model/fw_utils consumers
  • Review the added regression tests

The updated PR looks clean and correct. The added tests address the one gap flagged in the earlier round.

Correctness — confirmed

  • The guard isinstance(self.model_path, str) and not self.model_path.startswith("s3://") correctly scopes _local_download_dir to real local paths, and os.makedirs(..., exist_ok=True) satisfies the os.path.exists(...) and os.path.isdir(...) check in fw_utils._tmpdir/repack_model (sagemaker-core/src/sagemaker/core/fw_utils.py:450-463).
  • The behavior change for s3:// paths is the right call and, as the author noted, actually fixes a latent bug: previously an S3 model_path (from TrainingJob/ModelTrainer, e.g. model_builder.py:3064,3072) would be assigned verbatim and then trip the same ValueError in _tmpdir. Both consumers (fw_utils.py:462, common_utils.py:595-601) only use it as the dir= parent for tempfile.mkdtemp, so leaving it unset falls back to the system temp dir — no code reads it as an S3 URI. ✅
  • exist_ok=True keeps build() idempotent on re-run. ✅

Tests — good coverage

  • test_local_model_path_is_created_and_used and test_s3_model_path_leaves_local_download_dir_unset cover both branches directly, using a real SessionSettings() so the local_download_dir property (not just the mock attribute) is exercised. This is exactly the regression guard the source_code repack path needed. ✅

Minor (non-blocking)

  • The file:// edge case is still theoretically present but, as discussed, unreachable — model_path is only ever a plain filesystem path and file:// is prepended solely for s3_upload_path. Fine to leave out of scope.

No blocking issues. Ship it.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

Both test failures are flaky and unrelated to this PR (which only touches sagemaker-serve/model_builder.py):

  • mlopstest_feature_processor_transform_online_only_store_ingestion — a ConcurrentModificationException in the shaded AWS SDK AttributeMap when the Feature Store Spark connector builds its client concurrently across executor threads.
  • us-east-1test_inspect_ai_upload_benchmarks — the pipeline execution failed server-side with Pipeline ... has been modified since your last read (a concurrent-modification conflict under parallel test runs).

Both are concurrency races in infra/service code, not regressions from this change. Retrying should turn them green.

@lucasjia-aws
lucasjia-aws merged commit 748910e into aws:masterAug 3, 2026
16 of 21 checks passed
@github-actionsgithub-actionsBot mentioned this pull request Aug 10, 2026
Sign up for freeto 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.

2 participants

@lucasjia-aws@mujtaba1747
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(serve): create local model_path dir before using it as download dir - #6147

Merged
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder
Aug 3, 2026
Merged

fix(serve): create local model_path dir before using it as download dir#6147
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder

Conversation

@lucasjia-aws

Copy link
Copy Markdown
Collaborator

ModelBuilder.build() assigned the default model_path (/tmp/sagemaker/model-builder/) to settings._local_download_dir without creating it on disk, so repack_model()'s _tmpdir() validation raised "Inputted directory ... does not exist" for source_code repack builds. Only use model_path as the local download dir when it is a local path, creating it first; skip s3:// URIs.

Issue #, if available:

Description of changes:

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

ModelBuilder.build() assigned the default model_path
(/tmp/sagemaker/model-builder/<uuid>) to settings._local_download_dir
without creating it on disk, so repack_model()'s _tmpdir() validation
raised "Inputted directory ... does not exist" for source_code repack
builds. Only use model_path as the local download dir when it is a
local path, creating it first; skip s3:// URIs.
@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 50s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff
  • Review the change for correctness, best practices, security, tests

The fix looks correct and well-targeted. ModelBuilder's default model_path is a local dir (/tmp/sagemaker/model-builder/<uuid>) created lazily, and repack_model()'s _tmpdir() validation requires it to exist on disk — so creating it before wiring it into settings._local_download_dir resolves the "Inputted directory ... does not exist" error.

A few things I verified:

  • os is already imported (model_builder.py:22), so os.makedirs is safe.
  • ✅ The isinstance(self.model_path, str) guard correctly avoids the case where model_path could be non-string, and not startswith("s3://") correctly skips remote artifacts. This is consistent with the existing self.model_path.startswith("s3://") checks elsewhere in the file (lines 1883, 1918).
  • os.makedirs(..., exist_ok=True) is idempotent, so re-running build() won't raise.

Minor considerations (non-blocking)

  1. Behavior change for s3:// paths: Previously _local_download_dir was set unconditionally to self.model_path (even when it was an s3:// URI, e.g. from a TrainingJob/ModelTrainer). Now it's left unset for s3:// paths. This is almost certainly the right behavior (a local download dir should never be an S3 URI), but it is a subtle behavior change — worth confirming no downstream code relied on _local_download_dir holding the S3 URI.

  2. file:// prefix: The guard treats file://... paths as local and would call os.makedirs("file://..."), creating a literal file:/ directory. Looking at the code, model_path is stored as a plain path and file:// is only prepended when building s3_upload_path (line 1788), so this shouldn't occur in practice — just flagging it as a latent edge case if a user ever passes a file://model_path.

  3. Tests: No test accompanies this change. A small unit test asserting that (a) a local model_path is created on disk and assigned to settings._local_download_dir, and (b) an s3://model_path leaves it unset, would guard against regressions of exactly the bug this fixes.

Overall this is a small, sensible bug fix. The main suggestion is adding a regression test for the source_code repack path.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

1. s3:// behavior change — Intentional and safe. settings.local_download_dir is only ever consumed as the parent dir for tempfile.mkdtemp() in repack_model() and fw_utils — nothing reads it as an S3 URI. The previous unconditional assignment was actually buggy for an S3 model_path (e.g. from a TrainingJob/ModelTrainer): _tmpdir() would call os.path.exists("s3://...") and raise the same ValueError. Leaving it unset for S3 paths falls back to the system temp dir, which is the correct behavior.

2. file:// prefix — Not reachable in practice. model_path is always stored as a plain filesystem path; file:// is only prepended when constructing s3_upload_path, so os.makedirs("file://...") can't occur here. Agreed it's a latent edge case, but out of scope for this fix.

3. Regression test — Added TestModelBuilderLocalDownloadDir in test_model_builder_core.py covering both branches: a local model_path is created on disk and wired into settings.local_download_dir, and an s3://model_path leaves it unset.

@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 46s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff (/tmp/pr.diff)
  • Review the fix for correctness against repack_model/fw_utils consumers
  • Review the added regression tests

The updated PR looks clean and correct. The added tests address the one gap flagged in the earlier round.

Correctness — confirmed

  • The guard isinstance(self.model_path, str) and not self.model_path.startswith("s3://") correctly scopes _local_download_dir to real local paths, and os.makedirs(..., exist_ok=True) satisfies the os.path.exists(...) and os.path.isdir(...) check in fw_utils._tmpdir/repack_model (sagemaker-core/src/sagemaker/core/fw_utils.py:450-463).
  • The behavior change for s3:// paths is the right call and, as the author noted, actually fixes a latent bug: previously an S3 model_path (from TrainingJob/ModelTrainer, e.g. model_builder.py:3064,3072) would be assigned verbatim and then trip the same ValueError in _tmpdir. Both consumers (fw_utils.py:462, common_utils.py:595-601) only use it as the dir= parent for tempfile.mkdtemp, so leaving it unset falls back to the system temp dir — no code reads it as an S3 URI. ✅
  • exist_ok=True keeps build() idempotent on re-run. ✅

Tests — good coverage

  • test_local_model_path_is_created_and_used and test_s3_model_path_leaves_local_download_dir_unset cover both branches directly, using a real SessionSettings() so the local_download_dir property (not just the mock attribute) is exercised. This is exactly the regression guard the source_code repack path needed. ✅

Minor (non-blocking)

  • The file:// edge case is still theoretically present but, as discussed, unreachable — model_path is only ever a plain filesystem path and file:// is prepended solely for s3_upload_path. Fine to leave out of scope.

No blocking issues. Ship it.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

Both test failures are flaky and unrelated to this PR (which only touches sagemaker-serve/model_builder.py):

  • mlopstest_feature_processor_transform_online_only_store_ingestion — a ConcurrentModificationException in the shaded AWS SDK AttributeMap when the Feature Store Spark connector builds its client concurrently across executor threads.
  • us-east-1test_inspect_ai_upload_benchmarks — the pipeline execution failed server-side with Pipeline ... has been modified since your last read (a concurrent-modification conflict under parallel test runs).

Both are concurrency races in infra/service code, not regressions from this change. Retrying should turn them green.

@lucasjia-aws
lucasjia-aws merged commit 748910e into aws:masterAug 3, 2026
16 of 21 checks passed
@github-actionsgithub-actionsBot mentioned this pull request Aug 10, 2026
Sign up for freeto 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.

2 participants

@lucasjia-aws@mujtaba1747
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(serve): create local model_path dir before using it as download dir - #6147

Merged
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder
Aug 3, 2026
Merged

fix(serve): create local model_path dir before using it as download dir#6147
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder

Conversation

@lucasjia-aws

Copy link
Copy Markdown
Collaborator

ModelBuilder.build() assigned the default model_path (/tmp/sagemaker/model-builder/) to settings._local_download_dir without creating it on disk, so repack_model()'s _tmpdir() validation raised "Inputted directory ... does not exist" for source_code repack builds. Only use model_path as the local download dir when it is a local path, creating it first; skip s3:// URIs.

Issue #, if available:

Description of changes:

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

ModelBuilder.build() assigned the default model_path
(/tmp/sagemaker/model-builder/<uuid>) to settings._local_download_dir
without creating it on disk, so repack_model()'s _tmpdir() validation
raised "Inputted directory ... does not exist" for source_code repack
builds. Only use model_path as the local download dir when it is a
local path, creating it first; skip s3:// URIs.
@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 50s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff
  • Review the change for correctness, best practices, security, tests

The fix looks correct and well-targeted. ModelBuilder's default model_path is a local dir (/tmp/sagemaker/model-builder/<uuid>) created lazily, and repack_model()'s _tmpdir() validation requires it to exist on disk — so creating it before wiring it into settings._local_download_dir resolves the "Inputted directory ... does not exist" error.

A few things I verified:

  • os is already imported (model_builder.py:22), so os.makedirs is safe.
  • ✅ The isinstance(self.model_path, str) guard correctly avoids the case where model_path could be non-string, and not startswith("s3://") correctly skips remote artifacts. This is consistent with the existing self.model_path.startswith("s3://") checks elsewhere in the file (lines 1883, 1918).
  • os.makedirs(..., exist_ok=True) is idempotent, so re-running build() won't raise.

Minor considerations (non-blocking)

  1. Behavior change for s3:// paths: Previously _local_download_dir was set unconditionally to self.model_path (even when it was an s3:// URI, e.g. from a TrainingJob/ModelTrainer). Now it's left unset for s3:// paths. This is almost certainly the right behavior (a local download dir should never be an S3 URI), but it is a subtle behavior change — worth confirming no downstream code relied on _local_download_dir holding the S3 URI.

  2. file:// prefix: The guard treats file://... paths as local and would call os.makedirs("file://..."), creating a literal file:/ directory. Looking at the code, model_path is stored as a plain path and file:// is only prepended when building s3_upload_path (line 1788), so this shouldn't occur in practice — just flagging it as a latent edge case if a user ever passes a file://model_path.

  3. Tests: No test accompanies this change. A small unit test asserting that (a) a local model_path is created on disk and assigned to settings._local_download_dir, and (b) an s3://model_path leaves it unset, would guard against regressions of exactly the bug this fixes.

Overall this is a small, sensible bug fix. The main suggestion is adding a regression test for the source_code repack path.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

1. s3:// behavior change — Intentional and safe. settings.local_download_dir is only ever consumed as the parent dir for tempfile.mkdtemp() in repack_model() and fw_utils — nothing reads it as an S3 URI. The previous unconditional assignment was actually buggy for an S3 model_path (e.g. from a TrainingJob/ModelTrainer): _tmpdir() would call os.path.exists("s3://...") and raise the same ValueError. Leaving it unset for S3 paths falls back to the system temp dir, which is the correct behavior.

2. file:// prefix — Not reachable in practice. model_path is always stored as a plain filesystem path; file:// is only prepended when constructing s3_upload_path, so os.makedirs("file://...") can't occur here. Agreed it's a latent edge case, but out of scope for this fix.

3. Regression test — Added TestModelBuilderLocalDownloadDir in test_model_builder_core.py covering both branches: a local model_path is created on disk and wired into settings.local_download_dir, and an s3://model_path leaves it unset.

@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 46s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff (/tmp/pr.diff)
  • Review the fix for correctness against repack_model/fw_utils consumers
  • Review the added regression tests

The updated PR looks clean and correct. The added tests address the one gap flagged in the earlier round.

Correctness — confirmed

  • The guard isinstance(self.model_path, str) and not self.model_path.startswith("s3://") correctly scopes _local_download_dir to real local paths, and os.makedirs(..., exist_ok=True) satisfies the os.path.exists(...) and os.path.isdir(...) check in fw_utils._tmpdir/repack_model (sagemaker-core/src/sagemaker/core/fw_utils.py:450-463).
  • The behavior change for s3:// paths is the right call and, as the author noted, actually fixes a latent bug: previously an S3 model_path (from TrainingJob/ModelTrainer, e.g. model_builder.py:3064,3072) would be assigned verbatim and then trip the same ValueError in _tmpdir. Both consumers (fw_utils.py:462, common_utils.py:595-601) only use it as the dir= parent for tempfile.mkdtemp, so leaving it unset falls back to the system temp dir — no code reads it as an S3 URI. ✅
  • exist_ok=True keeps build() idempotent on re-run. ✅

Tests — good coverage

  • test_local_model_path_is_created_and_used and test_s3_model_path_leaves_local_download_dir_unset cover both branches directly, using a real SessionSettings() so the local_download_dir property (not just the mock attribute) is exercised. This is exactly the regression guard the source_code repack path needed. ✅

Minor (non-blocking)

  • The file:// edge case is still theoretically present but, as discussed, unreachable — model_path is only ever a plain filesystem path and file:// is prepended solely for s3_upload_path. Fine to leave out of scope.

No blocking issues. Ship it.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

Both test failures are flaky and unrelated to this PR (which only touches sagemaker-serve/model_builder.py):

  • mlopstest_feature_processor_transform_online_only_store_ingestion — a ConcurrentModificationException in the shaded AWS SDK AttributeMap when the Feature Store Spark connector builds its client concurrently across executor threads.
  • us-east-1test_inspect_ai_upload_benchmarks — the pipeline execution failed server-side with Pipeline ... has been modified since your last read (a concurrent-modification conflict under parallel test runs).

Both are concurrency races in infra/service code, not regressions from this change. Retrying should turn them green.

@lucasjia-aws
lucasjia-aws merged commit 748910e into aws:masterAug 3, 2026
16 of 21 checks passed
@github-actionsgithub-actionsBot mentioned this pull request Aug 10, 2026
Sign up for freeto 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.

2 participants

@lucasjia-aws@mujtaba1747
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(serve): create local model_path dir before using it as download dir - #6147

Merged
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder
Aug 3, 2026
Merged

fix(serve): create local model_path dir before using it as download dir#6147
lucasjia-aws merged 2 commits into
aws:masterfrom
lucasjia-aws:fix/ModelBuilder

Conversation

@lucasjia-aws

Copy link
Copy Markdown
Collaborator

ModelBuilder.build() assigned the default model_path (/tmp/sagemaker/model-builder/) to settings._local_download_dir without creating it on disk, so repack_model()'s _tmpdir() validation raised "Inputted directory ... does not exist" for source_code repack builds. Only use model_path as the local download dir when it is a local path, creating it first; skip s3:// URIs.

Issue #, if available:

Description of changes:

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

ModelBuilder.build() assigned the default model_path
(/tmp/sagemaker/model-builder/<uuid>) to settings._local_download_dir
without creating it on disk, so repack_model()'s _tmpdir() validation
raised "Inputted directory ... does not exist" for source_code repack
builds. Only use model_path as the local download dir when it is a
local path, creating it first; skip s3:// URIs.
@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 50s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff
  • Review the change for correctness, best practices, security, tests

The fix looks correct and well-targeted. ModelBuilder's default model_path is a local dir (/tmp/sagemaker/model-builder/<uuid>) created lazily, and repack_model()'s _tmpdir() validation requires it to exist on disk — so creating it before wiring it into settings._local_download_dir resolves the "Inputted directory ... does not exist" error.

A few things I verified:

  • os is already imported (model_builder.py:22), so os.makedirs is safe.
  • ✅ The isinstance(self.model_path, str) guard correctly avoids the case where model_path could be non-string, and not startswith("s3://") correctly skips remote artifacts. This is consistent with the existing self.model_path.startswith("s3://") checks elsewhere in the file (lines 1883, 1918).
  • os.makedirs(..., exist_ok=True) is idempotent, so re-running build() won't raise.

Minor considerations (non-blocking)

  1. Behavior change for s3:// paths: Previously _local_download_dir was set unconditionally to self.model_path (even when it was an s3:// URI, e.g. from a TrainingJob/ModelTrainer). Now it's left unset for s3:// paths. This is almost certainly the right behavior (a local download dir should never be an S3 URI), but it is a subtle behavior change — worth confirming no downstream code relied on _local_download_dir holding the S3 URI.

  2. file:// prefix: The guard treats file://... paths as local and would call os.makedirs("file://..."), creating a literal file:/ directory. Looking at the code, model_path is stored as a plain path and file:// is only prepended when building s3_upload_path (line 1788), so this shouldn't occur in practice — just flagging it as a latent edge case if a user ever passes a file://model_path.

  3. Tests: No test accompanies this change. A small unit test asserting that (a) a local model_path is created on disk and assigned to settings._local_download_dir, and (b) an s3://model_path leaves it unset, would guard against regressions of exactly the bug this fixes.

Overall this is a small, sensible bug fix. The main suggestion is adding a regression test for the source_code repack path.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

1. s3:// behavior change — Intentional and safe. settings.local_download_dir is only ever consumed as the parent dir for tempfile.mkdtemp() in repack_model() and fw_utils — nothing reads it as an S3 URI. The previous unconditional assignment was actually buggy for an S3 model_path (e.g. from a TrainingJob/ModelTrainer): _tmpdir() would call os.path.exists("s3://...") and raise the same ValueError. Leaving it unset for S3 paths falls back to the system temp dir, which is the correct behavior.

2. file:// prefix — Not reachable in practice. model_path is always stored as a plain filesystem path; file:// is only prepended when constructing s3_upload_path, so os.makedirs("file://...") can't occur here. Agreed it's a latent edge case, but out of scope for this fix.

3. Regression test — Added TestModelBuilderLocalDownloadDir in test_model_builder_core.py covering both branches: a local model_path is created on disk and wired into settings.local_download_dir, and an s3://model_path leaves it unset.

@github-actions

github-actionsBot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @lucasjia-aws's task in 46s —— View job


PR Review: create local model_path dir before using it as download dir

  • Read the PR diff (/tmp/pr.diff)
  • Review the fix for correctness against repack_model/fw_utils consumers
  • Review the added regression tests

The updated PR looks clean and correct. The added tests address the one gap flagged in the earlier round.

Correctness — confirmed

  • The guard isinstance(self.model_path, str) and not self.model_path.startswith("s3://") correctly scopes _local_download_dir to real local paths, and os.makedirs(..., exist_ok=True) satisfies the os.path.exists(...) and os.path.isdir(...) check in fw_utils._tmpdir/repack_model (sagemaker-core/src/sagemaker/core/fw_utils.py:450-463).
  • The behavior change for s3:// paths is the right call and, as the author noted, actually fixes a latent bug: previously an S3 model_path (from TrainingJob/ModelTrainer, e.g. model_builder.py:3064,3072) would be assigned verbatim and then trip the same ValueError in _tmpdir. Both consumers (fw_utils.py:462, common_utils.py:595-601) only use it as the dir= parent for tempfile.mkdtemp, so leaving it unset falls back to the system temp dir — no code reads it as an S3 URI. ✅
  • exist_ok=True keeps build() idempotent on re-run. ✅

Tests — good coverage

  • test_local_model_path_is_created_and_used and test_s3_model_path_leaves_local_download_dir_unset cover both branches directly, using a real SessionSettings() so the local_download_dir property (not just the mock attribute) is exercised. This is exactly the regression guard the source_code repack path needed. ✅

Minor (non-blocking)

  • The file:// edge case is still theoretically present but, as discussed, unreachable — model_path is only ever a plain filesystem path and file:// is prepended solely for s3_upload_path. Fine to leave out of scope.

No blocking issues. Ship it.

@lucasjia-aws

Copy link
Copy Markdown
CollaboratorAuthor

Both test failures are flaky and unrelated to this PR (which only touches sagemaker-serve/model_builder.py):

  • mlopstest_feature_processor_transform_online_only_store_ingestion — a ConcurrentModificationException in the shaded AWS SDK AttributeMap when the Feature Store Spark connector builds its client concurrently across executor threads.
  • us-east-1test_inspect_ai_upload_benchmarks — the pipeline execution failed server-side with Pipeline ... has been modified since your last read (a concurrent-modification conflict under parallel test runs).

Both are concurrency races in infra/service code, not regressions from this change. Retrying should turn them green.

@lucasjia-aws
lucasjia-aws merged commit 748910e into aws:masterAug 3, 2026
16 of 21 checks passed
@github-actionsgithub-actionsBot mentioned this pull request Aug 10, 2026
Sign up for freeto 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.

2 participants

@lucasjia-aws@mujtaba1747