Repository navigation
[v3] FrameworkProcessor and ModelTrainer: 4 regressions (including dropping CodeArtifact support) from v2 migration #5765
Description
PySDK Version
- PySDK V2 (2.x)
- PySDK V3 (3.x)
Additional context
The following four issues were found during a migration from sagemaker==2.257.1 to sagemaker==3.7.1, moving training jobs from sagemaker.pytorch.PyTorch to sagemaker.train.ModelTrainer and processing jobs from sagemaker.pytorch.processing.PyTorchProcessor to sagemaker.core.processing.FrameworkProcessor.
Describe the bug
Four regressions found when migrating from v2 to v3, specifically around FrameworkProcessor (processing jobs) and ModelTrainer (training jobs). All four worked correctly in v2.
System information
- SageMaker Python SDK version: 3.7.1
- Framework name: PyTorch
- Framework version: 2.10
- Python version: 3.13
- CPU or GPU: Both
- Custom Docker image: N
Bug 1: wait=True does not respect sagemaker session
Affects: ModelTrainer.train(wait=True) and FrameworkProcessor.run(wait=True)
ProcessingJob.refresh() and TrainingJob.refresh() use Base.get_sagemaker_client() — a global/default client — instead of the sagemaker_session passed to the processor/trainer. This fails with NoCredentialsError when using assumed-role sessions (via STS).
To reproduce:
import boto3
from sagemaker.core.helper.session_helper import Session
from sagemaker.core.processing import FrameworkProcessor
from sagemaker.train import ModelTrainer
from sagemaker.core.training.configs import Compute, SourceCode
# Assumed-role session
sts = boto3.client("sts")
assumed = sts.assume_role(RoleArn="arn:aws:iam::123456789:role/MyRole", RoleSessionName="test")
creds = assumed["Credentials"]
assumed_session = boto3.Session(
aws_access_key_id=creds["AccessKeyId"],
aws_secret_access_key=creds["SecretAccessKey"],
aws_session_token=creds["SessionToken"],
region_name="us-west-2",
)
sm_session = Session(boto_session=assumed_session)
# FrameworkProcessor — job created OK, wait fails
processor = FrameworkProcessor(
image_uri="763104351884.dkr.ecr.us-west-2.amazonaws.com/pytorch-training:2.10-cpu-py313",
command=["python3"],
role="arn:aws:iam::123456789:role/MyRole",
instance_count=1,
instance_type="ml.m5.xlarge",
sagemaker_session=sm_session,
)
processor.run(code="my_script.py", source_dir="src", wait=True)
# → NoCredentialsError
# ModelTrainer — same issue
trainer = ModelTrainer(
training_image="763104351884.dkr.ecr.us-west-2.amazonaws.com/pytorch-training:2.10-cpu-py313",
role="arn:aws:iam::123456789:role/MyRole",
source_code=SourceCode(entry_script="train.py", source_dir="src"),
compute=Compute(instance_type="ml.m5.xlarge", instance_count=1),
sagemaker_session=sm_session,
)
trainer.train(wait=True)
# → NoCredentialsErrorRoot cause (sagemaker/core/resources.py):
# ProcessingJob.refresh() / TrainingJob.refresh()
client = Base.get_sagemaker_client() # ← ignores the session
response = client.describe_processing_job(**operation_input_args)v2 behaviour — ProcessingJob.wait() used the session directly:
def wait(self, logs=True):
if logs:
self.sagemaker_session.logs_for_processing_job(self.job_name, wait=True)
else:
self.sagemaker_session.wait_for_processing_job(self.job_name)Bug 2: FrameworkProcessor.code_location is accepted but ignored
FrameworkProcessor.__init__ accepts code_location and stores it as self.code_location. The docstring states it controls where code is uploaded. However, _package_code ignores it and always uploads to self.sagemaker_session.default_bucket().
To reproduce:
processor = FrameworkProcessor(
image_uri="763104351884.dkr.ecr.us-west-2.amazonaws.com/pytorch-training:2.10-cpu-py313",
command=["python3"],
role="arn:aws:iam::123456789:role/MyRole",
instance_count=1,
instance_type="ml.m5.xlarge",
code_location="s3://my-custom-bucket", # ← ignored
)
processor.run(code="my_script.py", source_dir="src", wait=False)
# Code uploads to s3://sagemaker-us-west-2-123456789/... instead of s3://my-custom-bucket/...Root cause (sagemaker-core/src/sagemaker/core/processing.py, _package_code):
s3_uri = s3.s3_path_join(
"s3://",
self.sagemaker_session.default_bucket(), # ← always uses default bucket
self.sagemaker_session.default_bucket_prefix or "",
job_name, "source", "sourcedir.tar.gz",
)self.code_location is never referenced.
v2 behaviour — FrameworkProcessor delegated to an estimator that honored code_location:
# v2 FrameworkProcessor._create_estimator
return self.estimator_cls(
...
code_location=self.code_location,
...
)Note: ModelTrainer does not offer code_location at all — it always uses session.default_bucket(). Suggested fix: either remove code_location from FrameworkProcessor to align with ModelTrainer, or update _package_code to use it when set.
Bugs 3 and 4 are both about losing the ability to install requirements.txt dependencies from a CodeArtifact repository.
- PyTorch training and inference containers supported this via the
CA_REPOSITORY_ARNenvironment variable (see [feature-request] Support installing dependencies in requirements.txt from CodeArtifact for both training/inference SageMaker Containers deep-learning-containers#2509 for details) - feature: Add optional CodeArtifact login to FrameworkProcessing job script #4145 extended that support to processing jobs by exposing
codeartifact_repo_arnonFrameworkProcessor.run()
For context, the new ray-based inference containers are also adding codeartifact support via CA_REPOSITORY_ARN environment variable as can be seen in https://github.com/aws/deep-learning-containers/blob/0fc07f317a4db68ff728274070fbe332dde1ca26/scripts/ray/sagemaker_serve.py#L68
Bug 3: CodeArtifact support missing from FrameworkProcessor
In v2, FrameworkProcessor.run() accepted codeartifact_repo_arn (added in PR #4145). This configured pip inside the container to authenticate with CodeArtifact before installing requirements.txt.
In v3, FrameworkProcessor.run() does not accept codeartifact_repo_arn, and _generate_framework_script has no CodeArtifact support. The generated runproc.sh runs pip install -r requirements.txt without authentication, failing for packages hosted on private CodeArtifact repositories.
To reproduce:
processor = FrameworkProcessor(
image_uri="763104351884.dkr.ecr.us-west-2.amazonaws.com/pytorch-training:2.10-cpu-py313",
command=["python3"],
role="arn:aws:iam::123456789:role/MyRole",
instance_count=1,
instance_type="ml.m5.xlarge",
)
# v2 supported: processor.run(..., codeartifact_repo_arn="arn:aws:codeartifact:us-west-2:123:repository/domain/repo")
# v3 does not — parameter doesn't exist
processor.run(code="my_script.py", source_dir="src", wait=False)
# Container fails: pip install -r requirements.txt → package not found (private CodeArtifact repo)v2 behaviour — _generate_framework_script injected CodeArtifact login into runproc.sh:
if [[ -f 'requirements.txt' ]]; then
if ! hash aws 2>/dev/null; then
echo "AWS CLI is not installed. Skipping CodeArtifact login."
else
aws codeartifact login --tool pip --domain {domain} --domain-owner {owner} --repository {repository} --region {region}
fi
pip install -r requirements.txt
fiSuggested fix: Port codeartifact_repo_arn and _get_codeartifact_command from v2's PR #4145 into v3's FrameworkProcessor.
Bug 4: ModelTrainer bypasses sagemaker-training-toolkit, losing CodeArtifact support for requirements.txt
Affects: ModelTrainer.train() with SourceCode(requirements="requirements.txt")
ModelTrainer overrides the container's ENTRYPOINT with its own sm_train.sh driver script. This bypasses the sagemaker-training-toolkit installed in the container, which handled requirements.txt installation with CodeArtifact support (via the CA_REPOSITORY_ARN environment variable, added in sagemaker-training-toolkit#187).
The v3 sm_train.sh template for requirements installation is a bare pip install:
# from sagemaker.train.templates.INSTALL_REQUIREMENTS
echo "Installing requirements"
$SM_PIP_CMD install -r {requirements_file}It does not check for CA_REPOSITORY_ARN or configure pip to use CodeArtifact. The env var is passed to the container but nothing reads it.
To reproduce:
from sagemaker.train import ModelTrainer
from sagemaker.core.training.configs import Compute, SourceCode
trainer = ModelTrainer(
training_image="763104351884.dkr.ecr.us-west-2.amazonaws.com/pytorch-training:2.10-cpu-py313",
role="arn:aws:iam::123456789:role/MyRole",
source_code=SourceCode(
entry_script="train.py",
source_dir="src",
requirements="requirements.txt", # ← installed without CodeArtifact
),
compute=Compute(instance_type="ml.m5.xlarge", instance_count=1),
environment={"CA_REPOSITORY_ARN": "arn:aws:codeartifact:us-west-2:123:repository/domain/repo"},
)
trainer.train(wait=False)
# Container runs: pip install -r requirements.txt (using public PyPI, not CodeArtifact)
# Fails in VPC-isolated environments where PyPI is unreachablev2 behaviour — the PyTorch estimator used the container's native entrypoint, which invoked sagemaker-training-toolkit. The toolkit checked CA_REPOSITORY_ARN, ran aws codeartifact login --tool pip, then installed requirements. This was added in sagemaker-training-toolkit v4.7.0 and tracked in deep-learning-containers#2509.
Suggested fix: The INSTALL_REQUIREMENTS template in sagemaker.train.templates should check for CA_REPOSITORY_ARN and configure pip accordingly before installing, matching the behaviour of sagemaker-training-toolkit.
Activity
[-][v3] FrameworkProcessor and ModelTrainer: 3 regressions from v2 migration[/-][+][v3] FrameworkProcessor and ModelTrainer: 4 regressions from v2 migration[/+]humanzz commentedon Apr 16, 2026
The following is a bit more context from an LLM-analysis I did on the codebase, along with historical context given I contributed the codeartifact support before, and proposal for solutions.
CodeArtifact & SageMaker: How It Worked, What Broke, and How to Fix It
The Problem CodeArtifact Solves
SageMaker training, processing, and inference containers support installing additional Python dependencies from a
requirements.txtfile bundled with user code. By default,pip installresolves packages from the public PyPI index, which requires internet access.CodeArtifact solves this by providing a private PyPI mirror. With CodeArtifact:
The mechanism is simple: set the
CA_REPOSITORY_ARNenvironment variable on the SageMaker job, and the container authenticates with CodeArtifact before runningpip install.How CodeArtifact Support Was Built (2023)
CodeArtifact support was contributed through a series of PRs across multiple repositories (see deep-learning-containers#2509 for the original feature request):
CA_REPOSITORY_ARN, use boto3 to get an auth token, build an authenticated pip index URL, pass it topip install -i <url>codeartifact_repo_arnto SDK v2'sFrameworkProcessor.run()for processing jobsThe core authentication logic (parse ARN → boto3
get_authorization_token→ build authenticated URL) was implemented identically in bothsagemaker-training-toolkitandsagemaker-inference-toolkit. The new DLC ray inference containers (scripts/ray/sagemaker_serve.py) later independently reimplemented the same pattern.The SDK v2 State: How Each Job Type Worked
The Clean Model: Container Owns the Lifecycle
In SDK v2, the SDK's role was simple for training, inference, and tuning: upload user code, set environment variables, and let the container handle everything else. The container's native entrypoint invoked the appropriate toolkit, which handled:
CA_REPOSITORY_ARNfrom the environmentrequirements.txtwith the authenticated pip indexThis worked because the toolkits were installed in the containers, boto3 was available, and the SDK didn't interfere with the container's entrypoint.
The Exception: Processing Jobs
Processing jobs were the one case where the SDK did override the container's behavior.
FrameworkProcessorgenerated its own bash script (runproc.sh) that handled code extraction and dependency installation. Because this script bypassed the toolkit, it needed its own CodeArtifact implementation.Since
runproc.shis bash, the SDK v2 used AWS CLI (aws codeartifact login --tool pip) rather than boto3. This was added in PR #4145.SDK v2 Summary
PyTorchestimatorpip install -i <url>)PyTorchModelpip install -i <url>)HyperparameterTunerpip install -i <url>)FrameworkProcessorrunproc.sh)aws codeartifact login)The key insight: only processing jobs bypassed the container's toolkit, and that's the only place the SDK needed its own CodeArtifact implementation.
What Broke in SDK v3
Training:
ModelTrainerNow Overrides the Entrypoint (Bug 4)The SDK v3
ModelTrainerfollows the same pattern thatFrameworkProcessorused — it overrides the container's entrypoint with its own SDK-generated script (sm_train.sh):This bypasses
sagemaker-training-toolkitentirely. The SDK'ssm_train.shreimplements environment setup, requirements installation, and script execution — but without CodeArtifact support:Source:
constants.py,templates.pyThe
CA_REPOSITORY_ARNenv var reaches the container but nothing reads it.Processing:
codeartifact_repo_arnNot Ported (Bug 3)The SDK v3
FrameworkProcessorwas rewritten insagemaker-corebut thecodeartifact_repo_arnparameter from PR #4145 was not ported. The generatedrunproc.shdoes a barepip installwithout authentication.Tuning: Not Affected (Due to an API Limitation)
The SDK v3
TunerwrapsModelTrainerbut cannot override the container entrypoint because the AWSCreateHyperParameterTuningJobAPI doesn't support it.The
CreateHyperParameterTuningJobAPI has aTrainingJobDefinitionfield, which might suggest it supports the same options asCreateTrainingJob. However, the types differ despite confusingly similar naming:ContainerEntrypoint?CreateTrainingJobAlgorithmSpecificationAlgorithmSpecificationCreateHyperParameterTuningJobTrainingJobDefinition.AlgorithmSpecificationHyperParameterAlgorithmSpecificationBoth fields are named
AlgorithmSpecification, but they map to different types.HyperParameterAlgorithmSpecificationonly hasTrainingImage,TrainingInputMode,AlgorithmName, andMetricDefinitions. This applies to bothTrainingJobDefinition(singular) andTrainingJobDefinitions(plural, for multi-algo tuning).Because of this, the Tuner falls back to the SDK v2-style approach: setting
sagemaker_programandsagemaker_submit_directoryas hyperparameters, letting the container's native toolkit handle everything — including CodeArtifact.Future risk: If AWS adds
ContainerEntrypointtoHyperParameterAlgorithmSpecification, the SDK team may update the Tuner to match ModelTrainer's approach, breaking CodeArtifact for tuning too.Inference: Not Affected (Yet)
The SDK v3 does not override inference container entrypoints.
sagemaker-inference-toolkitstill handlesCA_REPOSITORY_ARNat model server startup. However, if a future SDK v3 inference path follows the ModelTrainer pattern, it would break here too.SDK v3 Summary
ModelTrainersm_train.sh)ModelBuilderTuner(wrapsModelTrainer)FrameworkProcessorrunproc.sh)The pattern is clear: every time the SDK overrides the container entrypoint, CodeArtifact breaks.
The Ideal Long-Term Solution (SDK + DLC Updates)
The Root Problem
CodeArtifact authentication logic has been copy-pasted across 4+ codebases:
sagemaker-training-toolkit(boto3)sagemaker-inference-toolkit(boto3)sagemaker-python-sdkSDK v2 FrameworkProcessor (AWS CLI)deep-learning-containersraysagemaker_serve.py(boto3)Each time the SDK takes over a container's entrypoint, this logic needs to be reimplemented again. This doesn't scale.
Proposed Architecture
A dedicated, shared Python package (or well-known module) that handles "configure pip for CodeArtifact from environment variables":
Because the package declares
boto3as a dependency, installing it in a container automatically brings boto3 along — containers don't need to independently manage boto3.Requirements:
Usage from Python (toolkits, SDK driver scripts):
Usage from bash (SDK-generated scripts like
runproc.sh,sm_train.sh):What This Requires
This requires cross-team coordination, but it's the right long-term answer.
The Stopgap Solution (SDK-Only Updates)
Given the current state — the SDK uploads custom entrypoint scripts that bypass the toolkit — we need a solution that works now, without waiting for container changes.
Design: A Self-Contained Python Script
A single Python script, uploaded by the SDK as part of its driver payload, that handles CodeArtifact authentication. It:
CA_REPOSITORY_ARNis set — if not, does nothingCA_REPOSITORY_ARNis set but neither boto3 nor AWS CLI is available — silent failure is worse than a clear errorHow It's Used
For training (
ModelTrainer'ssm_train.sh):The script is uploaded as part of
sm_drivers/scripts/. TheINSTALL_REQUIREMENTStemplate becomes:For processing (
FrameworkProcessor'srunproc.sh):The script is embedded in the source tarball or uploaded alongside it. The generated script becomes:
Same script, both paths. No duplication.
What This Doesn't Require
sagemaker-training-toolkitorsagemaker-inference-toolkitBehavior Matrix
CA_REPOSITORY_ARNset?pip install(no CodeArtifact)pip install -i <authenticated_url>(boto3)aws codeartifact loginthenpip install(CLI)API Enhancement (Optional Layer)
On top of the stopgap script, the SDK could expose
codeartifact_repo_arnas a first-class parameter:This would:
CA_REPOSITORY_ARNin the container environmentinstall_requirements.pyscript is included in the uploadAppendix: Container Inventory
Current Containers (DLC master branch)
New Containers (DLC main branch)
sagemaker_serve.pyThe new DLC base images do NOT include boto3 or awscli. This is why the stopgap script's fallback chain (boto3 → CLI → hard fail) matters — and why the long-term solution uses a shared package that declares boto3 as its own dependency, so installing the package in a container automatically brings boto3 along.
Appendix: The Three Existing Implementations
All three use the same core logic — parse the ARN, get a token, build an authenticated URL — but implemented independently:
1.
sagemaker-training-toolkit(Python/boto3)2. SDK v2 FrameworkProcessor (Bash/AWS CLI)
# Generated runproc.sh aws codeartifact login --tool pip --domain DOMAIN --domain-owner ACCOUNT --repository REPO --region REGION pip install -r requirements.txt3. DLC ray inference container (Python/boto3)
The stopgap script consolidates these into one implementation with graceful fallback.
[-][v3] FrameworkProcessor and ModelTrainer: 4 regressions from v2 migration[/-][+][v3] FrameworkProcessor and ModelTrainer: 4 regressions (including dropping CodeArtifact support) from v2 migration[/+]feat: add CodeArtifact support for ModelTrainer and FrameworkProcesso…
fix: wire FrameworkProcessor code_location into code upload paths
fix: wire FrameworkProcessor code_location into code upload paths (#5773
feat: add CodeArtifact support for ModelTrainer and FrameworkProcesso…
d-vesely commentedon May 8, 2026
I would like to add that I described another regression of the FrameworkProcessor in Issue #5735, regarding the
source_dirargument, which used to allow S3 URIs, but now requires a local path.