Skip to content

prepare_for_smd() missing return value causes CustomOrchestrator container health check failure #6200

Description

@lopezfelipe

PySDK Version

  • PySDK V2 (2.x)
  • PySDK V3 (3.x)

Describe the bug

When deploying a CustomOrchestrator as an Inference Component — as documented in the Build and deploy AI inference workflows with new enhancements to the Amazon SageMaker Python SDK blog post — the container fails its health check during startup with:

AttributeError: 'NoneType' object has no attribute 'encode'

The error occurs in the container's _pickle_file_integrity_check() at line 26 of check_integrity.py:

actual_hash_value=compute_hash(buffer=buffer, secret_key=secret_key)

where secret_key = os.environ.get("SAGEMAKER_SERVE_SECRET_KEY") is None.

Root cause:

prepare_for_smd() in model_server/smd/prepare.py computes the hash and writes metadata.json, but has no return statement:

defprepare_for_smd(model_path, shared_libs, dependencies, inference_spec=None) ->str:
...
hash_value=compute_hash(buffer=buffer)
withopen(str(code_dir.joinpath("metadata.json")), "wb") asmetadata:
metadata.write(_MetaData(hash_value).to_json())
# ← No return statement — returns None implicitly

In model_builder_servers.py L747:

self.secret_key=prepare_for_smd(...) # = None

Since self.secret_key is None, the SAGEMAKER_SERVE_SECRET_KEY environment variable is never set on the deployed Model/IC. At runtime, the container's integrity check reads the env var, gets None, and crashes.

Additionally, there is a version mismatch between:

  • The SDK's local check_integrity.py (uses plain SHA-256, no secret key)
  • The container image's bundled check_integrity.py (uses HMAC with a secret key)

To reproduce

fromsagemaker.serve.model_builderimportModelBuilder, SchemaBuilderfromsagemaker.serve.spec.inference_baseimportCustomOrchestratorfromsagemaker.core.inference_configimportResourceRequirementsfromsagemaker.core.helper.session_helperimportSession, get_execution_roleclassMyOrchestrator(CustomOrchestrator):
def__init__(self, endpoint_name, component_names):
super().__init__()
self.endpoint_name=endpoint_nameself.component_names=component_namesdefhandle(self, data, context=None):
importjsonresponse=self.client.invoke_endpoint(
EndpointName=self.endpoint_name,
InferenceComponentName=self.component_names[0],
Body=dataifisinstance(data, (str, bytes)) elsejson.dumps(data),
ContentType="application/json"
)
returnjson.loads(response["Body"].read())
role=get_execution_role()
sess=Session()
orchestrator=ModelBuilder(
inference_spec=MyOrchestrator(
endpoint_name="my-existing-endpoint",
component_names=["base-ic", "adapter-ic"],
),
dependencies={"auto": False, "custom": ["cloudpickle"]},
sagemaker_session=sess,
role_arn=role,
schema_builder=SchemaBuilder(sample_input="Test", sample_output={"generated_text": "test"}),
)
# Workaround for missing constructor fields (separate issue)orchestrator.resource_requirements=ResourceRequirements(
requests={"memory": 4096, "num_accelerators": 1, "copies": 1, "num_cpus": 2}
)
orchestrator.inference_component_name="my-orchestrator-ic"orchestrator.build()
# Verify secret_key is None after build:print(f"secret_key: {orchestrator.secret_key}") # Prints: secret_key: None# Deploy via boto3 (workaround for separate _deploy_for_ic bug):orchestrator_model_name=orchestrator.built_model.model_namesm_client=sess.sagemaker_clientsm_client.create_inference_component(
InferenceComponentName="my-orchestrator-ic",
EndpointName="my-existing-endpoint",
VariantName="AllTraffic",
Specification={
"ModelName": orchestrator_model_name,
"ComputeResourceRequirements": {
"NumberOfAcceleratorDevicesRequired": 1,
"MinMemoryRequiredInMb": 4096,
"NumberOfCpuCoresRequired": 2,
},
"StartupParameters": {
"ModelDataDownloadTimeoutInSeconds": 300,
"ContainerStartupHealthCheckTimeoutInSeconds": 300,
}
},
RuntimeConfig={"CopyCount": 1}
)
# IC fails health check — see CloudWatch logs below

Expected behavior

The CustomOrchestrator IC should pass its container health check and become InService. The SAGEMAKER_SERVE_SECRET_KEY should be correctly generated during build() and propagated to the container environment.

Screenshots or logs

CloudWatch logs from the IC's container (/aws/sagemaker/InferenceComponents/my-orchestrator-ic):

/opt/ml/model/code/inference.py:60 in <module>
│ ❱ 60 _run_preflight_diagnostics()
/opt/ml/model/code/inference.py:38 in _run_preflight_diagnostics
│ ❱ 38 │ _pickle_file_integrity_check()
/opt/ml/model/code/inference.py:57 in _pickle_file_integrity_check
│ ❱ 57 │ perform_integrity_check(buffer=buffer, metadata_path=metadata_path)
/opt/conda/lib/python3.12/site-packages/sagemaker/serve/validations/check_integrity.py:26 in perform_integrity_check
│ ❱ 26 │ actual_hash_value = compute_hash(buffer=buffer, secret_key=secret_key)
AttributeError: 'NoneType' object has no attribute 'encode'

The container then fails the ping health check and the IC never reaches InService.

System information

  • SageMaker Python SDK version: sagemaker-serve 1.20.0 (SDK V3)
  • Framework name: SageMaker Distribution (SMD) container for CustomOrchestrator
  • Framework version: sagemaker-distribution-prod:3.2.0-cpu
  • Python version: 3.12
  • CPU or GPU: GPU (ml.g6.12xlarge endpoint)
  • Custom Docker image (Y/N): N

Additional context

There appear to be two sub-issues:

  1. prepare_for_smd()** has no return statement** — it should return the computed hash (or a generated secret key) so that self.secret_key is set to a real value in model_builder_servers.py L747.
  2. Version mismatch between SDK and container — The SDK's local check_integrity.py uses plain SHA-256 (hashlib.sha256(buffer).hexdigest()), but the container image (sagemaker-distribution-prod:3.2.0-cpu) still has an older version that uses HMAC with a secret key (hmac.new(secret_key.encode(), msg=buffer, digestmod=hashlib.sha256)). These need to be aligned.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
       blocks
      (function() {
      function addCopyButtons() {
      document.querySelectorAll('pre code').forEach(function(codeBlock) {
      if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
      codeBlock.parentElement.setAttribute('data-copy-added', 'true');
      var btn = document.createElement('button');
      btn.textContent = 'Copy';
      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;';
      btn.onmouseover = function() { this.style.opacity = '1'; };
      btn.onmouseout = function() { this.style.opacity = '0.7'; };
      btn.onclick = function() {
      navigator.clipboard.writeText(codeBlock.textContent).then(function() {
      btn.textContent = 'Copied!';
      setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
      });
      };
      codeBlock.parentElement.style.position = 'relative';
      codeBlock.parentElement.appendChild(btn);
      });
      }
      addCopyButtons();
      // Re-run on dynamic content
      var observer = new MutationObserver(addCopyButtons);
      observer.observe(document.body, { childList: true, subtree: true });
      })();
      }
      } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
      })();
      (function(){
      try {
      var __m = "github.com";
      var __re = new RegExp('^' + "github\\.com" + '
      `prepare_for_smd()` missing return value causes `CustomOrchestrator` container health check failure · Issue #6200 · aws/sagemaker-python-sdk · GitHub
      Skip to content

      prepare_for_smd() missing return value causes CustomOrchestrator container health check failure #6200

      Description

      @lopezfelipe

      PySDK Version

      • PySDK V2 (2.x)
      • PySDK V3 (3.x)

      Describe the bug

      When deploying a CustomOrchestrator as an Inference Component — as documented in the Build and deploy AI inference workflows with new enhancements to the Amazon SageMaker Python SDK blog post — the container fails its health check during startup with:

      AttributeError: 'NoneType' object has no attribute 'encode'
      

      The error occurs in the container's _pickle_file_integrity_check() at line 26 of check_integrity.py:

      actual_hash_value=compute_hash(buffer=buffer, secret_key=secret_key)

      where secret_key = os.environ.get("SAGEMAKER_SERVE_SECRET_KEY") is None.

      Root cause:

      prepare_for_smd() in model_server/smd/prepare.py computes the hash and writes metadata.json, but has no return statement:

      defprepare_for_smd(model_path, shared_libs, dependencies, inference_spec=None) ->str:
      ...
      hash_value=compute_hash(buffer=buffer)
      withopen(str(code_dir.joinpath("metadata.json")), "wb") asmetadata:
      metadata.write(_MetaData(hash_value).to_json())
      # ← No return statement — returns None implicitly

      In model_builder_servers.py L747:

      self.secret_key=prepare_for_smd(...) # = None

      Since self.secret_key is None, the SAGEMAKER_SERVE_SECRET_KEY environment variable is never set on the deployed Model/IC. At runtime, the container's integrity check reads the env var, gets None, and crashes.

      Additionally, there is a version mismatch between:

      • The SDK's local check_integrity.py (uses plain SHA-256, no secret key)
      • The container image's bundled check_integrity.py (uses HMAC with a secret key)

      To reproduce

      fromsagemaker.serve.model_builderimportModelBuilder, SchemaBuilderfromsagemaker.serve.spec.inference_baseimportCustomOrchestratorfromsagemaker.core.inference_configimportResourceRequirementsfromsagemaker.core.helper.session_helperimportSession, get_execution_roleclassMyOrchestrator(CustomOrchestrator):
      def__init__(self, endpoint_name, component_names):
      super().__init__()
      self.endpoint_name=endpoint_nameself.component_names=component_namesdefhandle(self, data, context=None):
      importjsonresponse=self.client.invoke_endpoint(
      EndpointName=self.endpoint_name,
      InferenceComponentName=self.component_names[0],
      Body=dataifisinstance(data, (str, bytes)) elsejson.dumps(data),
      ContentType="application/json"
      )
      returnjson.loads(response["Body"].read())
      role=get_execution_role()
      sess=Session()
      orchestrator=ModelBuilder(
      inference_spec=MyOrchestrator(
      endpoint_name="my-existing-endpoint",
      component_names=["base-ic", "adapter-ic"],
      ),
      dependencies={"auto": False, "custom": ["cloudpickle"]},
      sagemaker_session=sess,
      role_arn=role,
      schema_builder=SchemaBuilder(sample_input="Test", sample_output={"generated_text": "test"}),
      )
      # Workaround for missing constructor fields (separate issue)orchestrator.resource_requirements=ResourceRequirements(
      requests={"memory": 4096, "num_accelerators": 1, "copies": 1, "num_cpus": 2}
      )
      orchestrator.inference_component_name="my-orchestrator-ic"orchestrator.build()
      # Verify secret_key is None after build:print(f"secret_key: {orchestrator.secret_key}") # Prints: secret_key: None# Deploy via boto3 (workaround for separate _deploy_for_ic bug):orchestrator_model_name=orchestrator.built_model.model_namesm_client=sess.sagemaker_clientsm_client.create_inference_component(
      InferenceComponentName="my-orchestrator-ic",
      EndpointName="my-existing-endpoint",
      VariantName="AllTraffic",
      Specification={
      "ModelName": orchestrator_model_name,
      "ComputeResourceRequirements": {
      "NumberOfAcceleratorDevicesRequired": 1,
      "MinMemoryRequiredInMb": 4096,
      "NumberOfCpuCoresRequired": 2,
      },
      "StartupParameters": {
      "ModelDataDownloadTimeoutInSeconds": 300,
      "ContainerStartupHealthCheckTimeoutInSeconds": 300,
      }
      },
      RuntimeConfig={"CopyCount": 1}
      )
      # IC fails health check — see CloudWatch logs below

      Expected behavior

      The CustomOrchestrator IC should pass its container health check and become InService. The SAGEMAKER_SERVE_SECRET_KEY should be correctly generated during build() and propagated to the container environment.

      Screenshots or logs

      CloudWatch logs from the IC's container (/aws/sagemaker/InferenceComponents/my-orchestrator-ic):

      /opt/ml/model/code/inference.py:60 in <module>
      │ ❱ 60 _run_preflight_diagnostics()
      /opt/ml/model/code/inference.py:38 in _run_preflight_diagnostics
      │ ❱ 38 │ _pickle_file_integrity_check()
      /opt/ml/model/code/inference.py:57 in _pickle_file_integrity_check
      │ ❱ 57 │ perform_integrity_check(buffer=buffer, metadata_path=metadata_path)
      /opt/conda/lib/python3.12/site-packages/sagemaker/serve/validations/check_integrity.py:26 in perform_integrity_check
      │ ❱ 26 │ actual_hash_value = compute_hash(buffer=buffer, secret_key=secret_key)
      AttributeError: 'NoneType' object has no attribute 'encode'
      

      The container then fails the ping health check and the IC never reaches InService.

      System information

      • SageMaker Python SDK version: sagemaker-serve 1.20.0 (SDK V3)
      • Framework name: SageMaker Distribution (SMD) container for CustomOrchestrator
      • Framework version: sagemaker-distribution-prod:3.2.0-cpu
      • Python version: 3.12
      • CPU or GPU: GPU (ml.g6.12xlarge endpoint)
      • Custom Docker image (Y/N): N

      Additional context

      There appear to be two sub-issues:

      1. prepare_for_smd()** has no return statement** — it should return the computed hash (or a generated secret key) so that self.secret_key is set to a real value in model_builder_servers.py L747.
      2. Version mismatch between SDK and container — The SDK's local check_integrity.py uses plain SHA-256 (hashlib.sha256(buffer).hexdigest()), but the container image (sagemaker-distribution-prod:3.2.0-cpu) still has an older version that uses HMAC with a secret key (hmac.new(secret_key.encode(), msg=buffer, digestmod=hashlib.sha256)). These need to be aligned.

      Metadata

      Metadata

      Assignees

      No one assigned

        Type

        No type

        Projects

        No projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' `prepare_for_smd()` missing return value causes `CustomOrchestrator` container health check failure · Issue #6200 · aws/sagemaker-python-sdk · GitHub
          Skip to content

          prepare_for_smd() missing return value causes CustomOrchestrator container health check failure #6200

          Description

          @lopezfelipe

          PySDK Version

          • PySDK V2 (2.x)
          • PySDK V3 (3.x)

          Describe the bug

          When deploying a CustomOrchestrator as an Inference Component — as documented in the Build and deploy AI inference workflows with new enhancements to the Amazon SageMaker Python SDK blog post — the container fails its health check during startup with:

          AttributeError: 'NoneType' object has no attribute 'encode'
          

          The error occurs in the container's _pickle_file_integrity_check() at line 26 of check_integrity.py:

          actual_hash_value=compute_hash(buffer=buffer, secret_key=secret_key)

          where secret_key = os.environ.get("SAGEMAKER_SERVE_SECRET_KEY") is None.

          Root cause:

          prepare_for_smd() in model_server/smd/prepare.py computes the hash and writes metadata.json, but has no return statement:

          defprepare_for_smd(model_path, shared_libs, dependencies, inference_spec=None) ->str:
          ...
          hash_value=compute_hash(buffer=buffer)
          withopen(str(code_dir.joinpath("metadata.json")), "wb") asmetadata:
          metadata.write(_MetaData(hash_value).to_json())
          # ← No return statement — returns None implicitly

          In model_builder_servers.py L747:

          self.secret_key=prepare_for_smd(...) # = None

          Since self.secret_key is None, the SAGEMAKER_SERVE_SECRET_KEY environment variable is never set on the deployed Model/IC. At runtime, the container's integrity check reads the env var, gets None, and crashes.

          Additionally, there is a version mismatch between:

          • The SDK's local check_integrity.py (uses plain SHA-256, no secret key)
          • The container image's bundled check_integrity.py (uses HMAC with a secret key)

          To reproduce

          fromsagemaker.serve.model_builderimportModelBuilder, SchemaBuilderfromsagemaker.serve.spec.inference_baseimportCustomOrchestratorfromsagemaker.core.inference_configimportResourceRequirementsfromsagemaker.core.helper.session_helperimportSession, get_execution_roleclassMyOrchestrator(CustomOrchestrator):
          def__init__(self, endpoint_name, component_names):
          super().__init__()
          self.endpoint_name=endpoint_nameself.component_names=component_namesdefhandle(self, data, context=None):
          importjsonresponse=self.client.invoke_endpoint(
          EndpointName=self.endpoint_name,
          InferenceComponentName=self.component_names[0],
          Body=dataifisinstance(data, (str, bytes)) elsejson.dumps(data),
          ContentType="application/json"
          )
          returnjson.loads(response["Body"].read())
          role=get_execution_role()
          sess=Session()
          orchestrator=ModelBuilder(
          inference_spec=MyOrchestrator(
          endpoint_name="my-existing-endpoint",
          component_names=["base-ic", "adapter-ic"],
          ),
          dependencies={"auto": False, "custom": ["cloudpickle"]},
          sagemaker_session=sess,
          role_arn=role,
          schema_builder=SchemaBuilder(sample_input="Test", sample_output={"generated_text": "test"}),
          )
          # Workaround for missing constructor fields (separate issue)orchestrator.resource_requirements=ResourceRequirements(
          requests={"memory": 4096, "num_accelerators": 1, "copies": 1, "num_cpus": 2}
          )
          orchestrator.inference_component_name="my-orchestrator-ic"orchestrator.build()
          # Verify secret_key is None after build:print(f"secret_key: {orchestrator.secret_key}") # Prints: secret_key: None# Deploy via boto3 (workaround for separate _deploy_for_ic bug):orchestrator_model_name=orchestrator.built_model.model_namesm_client=sess.sagemaker_clientsm_client.create_inference_component(
          InferenceComponentName="my-orchestrator-ic",
          EndpointName="my-existing-endpoint",
          VariantName="AllTraffic",
          Specification={
          "ModelName": orchestrator_model_name,
          "ComputeResourceRequirements": {
          "NumberOfAcceleratorDevicesRequired": 1,
          "MinMemoryRequiredInMb": 4096,
          "NumberOfCpuCoresRequired": 2,
          },
          "StartupParameters": {
          "ModelDataDownloadTimeoutInSeconds": 300,
          "ContainerStartupHealthCheckTimeoutInSeconds": 300,
          }
          },
          RuntimeConfig={"CopyCount": 1}
          )
          # IC fails health check — see CloudWatch logs below

          Expected behavior

          The CustomOrchestrator IC should pass its container health check and become InService. The SAGEMAKER_SERVE_SECRET_KEY should be correctly generated during build() and propagated to the container environment.

          Screenshots or logs

          CloudWatch logs from the IC's container (/aws/sagemaker/InferenceComponents/my-orchestrator-ic):

          /opt/ml/model/code/inference.py:60 in <module>
          │ ❱ 60 _run_preflight_diagnostics()
          /opt/ml/model/code/inference.py:38 in _run_preflight_diagnostics
          │ ❱ 38 │ _pickle_file_integrity_check()
          /opt/ml/model/code/inference.py:57 in _pickle_file_integrity_check
          │ ❱ 57 │ perform_integrity_check(buffer=buffer, metadata_path=metadata_path)
          /opt/conda/lib/python3.12/site-packages/sagemaker/serve/validations/check_integrity.py:26 in perform_integrity_check
          │ ❱ 26 │ actual_hash_value = compute_hash(buffer=buffer, secret_key=secret_key)
          AttributeError: 'NoneType' object has no attribute 'encode'
          

          The container then fails the ping health check and the IC never reaches InService.

          System information

          • SageMaker Python SDK version: sagemaker-serve 1.20.0 (SDK V3)
          • Framework name: SageMaker Distribution (SMD) container for CustomOrchestrator
          • Framework version: sagemaker-distribution-prod:3.2.0-cpu
          • Python version: 3.12
          • CPU or GPU: GPU (ml.g6.12xlarge endpoint)
          • Custom Docker image (Y/N): N

          Additional context

          There appear to be two sub-issues:

          1. prepare_for_smd()** has no return statement** — it should return the computed hash (or a generated secret key) so that self.secret_key is set to a real value in model_builder_servers.py L747.
          2. Version mismatch between SDK and container — The SDK's local check_integrity.py uses plain SHA-256 (hashlib.sha256(buffer).hexdigest()), but the container image (sagemaker-distribution-prod:3.2.0-cpu) still has an older version that uses HMAC with a secret key (hmac.new(secret_key.encode(), msg=buffer, digestmod=hashlib.sha256)). These need to be aligned.

          Metadata

          Metadata

          Assignees

          No one assigned

            Type

            No type

            Projects

            No projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

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

              prepare_for_smd() missing return value causes CustomOrchestrator container health check failure #6200

              Description

              @lopezfelipe

              PySDK Version

              • PySDK V2 (2.x)
              • PySDK V3 (3.x)

              Describe the bug

              When deploying a CustomOrchestrator as an Inference Component — as documented in the Build and deploy AI inference workflows with new enhancements to the Amazon SageMaker Python SDK blog post — the container fails its health check during startup with:

              AttributeError: 'NoneType' object has no attribute 'encode'
              

              The error occurs in the container's _pickle_file_integrity_check() at line 26 of check_integrity.py:

              actual_hash_value=compute_hash(buffer=buffer, secret_key=secret_key)

              where secret_key = os.environ.get("SAGEMAKER_SERVE_SECRET_KEY") is None.

              Root cause:

              prepare_for_smd() in model_server/smd/prepare.py computes the hash and writes metadata.json, but has no return statement:

              defprepare_for_smd(model_path, shared_libs, dependencies, inference_spec=None) ->str:
              ...
              hash_value=compute_hash(buffer=buffer)
              withopen(str(code_dir.joinpath("metadata.json")), "wb") asmetadata:
              metadata.write(_MetaData(hash_value).to_json())
              # ← No return statement — returns None implicitly

              In model_builder_servers.py L747:

              self.secret_key=prepare_for_smd(...) # = None

              Since self.secret_key is None, the SAGEMAKER_SERVE_SECRET_KEY environment variable is never set on the deployed Model/IC. At runtime, the container's integrity check reads the env var, gets None, and crashes.

              Additionally, there is a version mismatch between:

              • The SDK's local check_integrity.py (uses plain SHA-256, no secret key)
              • The container image's bundled check_integrity.py (uses HMAC with a secret key)

              To reproduce

              fromsagemaker.serve.model_builderimportModelBuilder, SchemaBuilderfromsagemaker.serve.spec.inference_baseimportCustomOrchestratorfromsagemaker.core.inference_configimportResourceRequirementsfromsagemaker.core.helper.session_helperimportSession, get_execution_roleclassMyOrchestrator(CustomOrchestrator):
              def__init__(self, endpoint_name, component_names):
              super().__init__()
              self.endpoint_name=endpoint_nameself.component_names=component_namesdefhandle(self, data, context=None):
              importjsonresponse=self.client.invoke_endpoint(
              EndpointName=self.endpoint_name,
              InferenceComponentName=self.component_names[0],
              Body=dataifisinstance(data, (str, bytes)) elsejson.dumps(data),
              ContentType="application/json"
              )
              returnjson.loads(response["Body"].read())
              role=get_execution_role()
              sess=Session()
              orchestrator=ModelBuilder(
              inference_spec=MyOrchestrator(
              endpoint_name="my-existing-endpoint",
              component_names=["base-ic", "adapter-ic"],
              ),
              dependencies={"auto": False, "custom": ["cloudpickle"]},
              sagemaker_session=sess,
              role_arn=role,
              schema_builder=SchemaBuilder(sample_input="Test", sample_output={"generated_text": "test"}),
              )
              # Workaround for missing constructor fields (separate issue)orchestrator.resource_requirements=ResourceRequirements(
              requests={"memory": 4096, "num_accelerators": 1, "copies": 1, "num_cpus": 2}
              )
              orchestrator.inference_component_name="my-orchestrator-ic"orchestrator.build()
              # Verify secret_key is None after build:print(f"secret_key: {orchestrator.secret_key}") # Prints: secret_key: None# Deploy via boto3 (workaround for separate _deploy_for_ic bug):orchestrator_model_name=orchestrator.built_model.model_namesm_client=sess.sagemaker_clientsm_client.create_inference_component(
              InferenceComponentName="my-orchestrator-ic",
              EndpointName="my-existing-endpoint",
              VariantName="AllTraffic",
              Specification={
              "ModelName": orchestrator_model_name,
              "ComputeResourceRequirements": {
              "NumberOfAcceleratorDevicesRequired": 1,
              "MinMemoryRequiredInMb": 4096,
              "NumberOfCpuCoresRequired": 2,
              },
              "StartupParameters": {
              "ModelDataDownloadTimeoutInSeconds": 300,
              "ContainerStartupHealthCheckTimeoutInSeconds": 300,
              }
              },
              RuntimeConfig={"CopyCount": 1}
              )
              # IC fails health check — see CloudWatch logs below

              Expected behavior

              The CustomOrchestrator IC should pass its container health check and become InService. The SAGEMAKER_SERVE_SECRET_KEY should be correctly generated during build() and propagated to the container environment.

              Screenshots or logs

              CloudWatch logs from the IC's container (/aws/sagemaker/InferenceComponents/my-orchestrator-ic):

              /opt/ml/model/code/inference.py:60 in <module>
              │ ❱ 60 _run_preflight_diagnostics()
              /opt/ml/model/code/inference.py:38 in _run_preflight_diagnostics
              │ ❱ 38 │ _pickle_file_integrity_check()
              /opt/ml/model/code/inference.py:57 in _pickle_file_integrity_check
              │ ❱ 57 │ perform_integrity_check(buffer=buffer, metadata_path=metadata_path)
              /opt/conda/lib/python3.12/site-packages/sagemaker/serve/validations/check_integrity.py:26 in perform_integrity_check
              │ ❱ 26 │ actual_hash_value = compute_hash(buffer=buffer, secret_key=secret_key)
              AttributeError: 'NoneType' object has no attribute 'encode'
              

              The container then fails the ping health check and the IC never reaches InService.

              System information

              • SageMaker Python SDK version: sagemaker-serve 1.20.0 (SDK V3)
              • Framework name: SageMaker Distribution (SMD) container for CustomOrchestrator
              • Framework version: sagemaker-distribution-prod:3.2.0-cpu
              • Python version: 3.12
              • CPU or GPU: GPU (ml.g6.12xlarge endpoint)
              • Custom Docker image (Y/N): N

              Additional context

              There appear to be two sub-issues:

              1. prepare_for_smd()** has no return statement** — it should return the computed hash (or a generated secret key) so that self.secret_key is set to a real value in model_builder_servers.py L747.
              2. Version mismatch between SDK and container — The SDK's local check_integrity.py uses plain SHA-256 (hashlib.sha256(buffer).hexdigest()), but the container image (sagemaker-distribution-prod:3.2.0-cpu) still has an older version that uses HMAC with a secret key (hmac.new(secret_key.encode(), msg=buffer, digestmod=hashlib.sha256)). These need to be aligned.

              Metadata

              Metadata

              Assignees

              No one assigned

                Type

                No type

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions

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

                  prepare_for_smd() missing return value causes CustomOrchestrator container health check failure #6200

                  Description

                  @lopezfelipe

                  PySDK Version

                  • PySDK V2 (2.x)
                  • PySDK V3 (3.x)

                  Describe the bug

                  When deploying a CustomOrchestrator as an Inference Component — as documented in the Build and deploy AI inference workflows with new enhancements to the Amazon SageMaker Python SDK blog post — the container fails its health check during startup with:

                  AttributeError: 'NoneType' object has no attribute 'encode'
                  

                  The error occurs in the container's _pickle_file_integrity_check() at line 26 of check_integrity.py:

                  actual_hash_value=compute_hash(buffer=buffer, secret_key=secret_key)

                  where secret_key = os.environ.get("SAGEMAKER_SERVE_SECRET_KEY") is None.

                  Root cause:

                  prepare_for_smd() in model_server/smd/prepare.py computes the hash and writes metadata.json, but has no return statement:

                  defprepare_for_smd(model_path, shared_libs, dependencies, inference_spec=None) ->str:
                  ...
                  hash_value=compute_hash(buffer=buffer)
                  withopen(str(code_dir.joinpath("metadata.json")), "wb") asmetadata:
                  metadata.write(_MetaData(hash_value).to_json())
                  # ← No return statement — returns None implicitly

                  In model_builder_servers.py L747:

                  self.secret_key=prepare_for_smd(...) # = None

                  Since self.secret_key is None, the SAGEMAKER_SERVE_SECRET_KEY environment variable is never set on the deployed Model/IC. At runtime, the container's integrity check reads the env var, gets None, and crashes.

                  Additionally, there is a version mismatch between:

                  • The SDK's local check_integrity.py (uses plain SHA-256, no secret key)
                  • The container image's bundled check_integrity.py (uses HMAC with a secret key)

                  To reproduce

                  fromsagemaker.serve.model_builderimportModelBuilder, SchemaBuilderfromsagemaker.serve.spec.inference_baseimportCustomOrchestratorfromsagemaker.core.inference_configimportResourceRequirementsfromsagemaker.core.helper.session_helperimportSession, get_execution_roleclassMyOrchestrator(CustomOrchestrator):
                  def__init__(self, endpoint_name, component_names):
                  super().__init__()
                  self.endpoint_name=endpoint_nameself.component_names=component_namesdefhandle(self, data, context=None):
                  importjsonresponse=self.client.invoke_endpoint(
                  EndpointName=self.endpoint_name,
                  InferenceComponentName=self.component_names[0],
                  Body=dataifisinstance(data, (str, bytes)) elsejson.dumps(data),
                  ContentType="application/json"
                  )
                  returnjson.loads(response["Body"].read())
                  role=get_execution_role()
                  sess=Session()
                  orchestrator=ModelBuilder(
                  inference_spec=MyOrchestrator(
                  endpoint_name="my-existing-endpoint",
                  component_names=["base-ic", "adapter-ic"],
                  ),
                  dependencies={"auto": False, "custom": ["cloudpickle"]},
                  sagemaker_session=sess,
                  role_arn=role,
                  schema_builder=SchemaBuilder(sample_input="Test", sample_output={"generated_text": "test"}),
                  )
                  # Workaround for missing constructor fields (separate issue)orchestrator.resource_requirements=ResourceRequirements(
                  requests={"memory": 4096, "num_accelerators": 1, "copies": 1, "num_cpus": 2}
                  )
                  orchestrator.inference_component_name="my-orchestrator-ic"orchestrator.build()
                  # Verify secret_key is None after build:print(f"secret_key: {orchestrator.secret_key}") # Prints: secret_key: None# Deploy via boto3 (workaround for separate _deploy_for_ic bug):orchestrator_model_name=orchestrator.built_model.model_namesm_client=sess.sagemaker_clientsm_client.create_inference_component(
                  InferenceComponentName="my-orchestrator-ic",
                  EndpointName="my-existing-endpoint",
                  VariantName="AllTraffic",
                  Specification={
                  "ModelName": orchestrator_model_name,
                  "ComputeResourceRequirements": {
                  "NumberOfAcceleratorDevicesRequired": 1,
                  "MinMemoryRequiredInMb": 4096,
                  "NumberOfCpuCoresRequired": 2,
                  },
                  "StartupParameters": {
                  "ModelDataDownloadTimeoutInSeconds": 300,
                  "ContainerStartupHealthCheckTimeoutInSeconds": 300,
                  }
                  },
                  RuntimeConfig={"CopyCount": 1}
                  )
                  # IC fails health check — see CloudWatch logs below

                  Expected behavior

                  The CustomOrchestrator IC should pass its container health check and become InService. The SAGEMAKER_SERVE_SECRET_KEY should be correctly generated during build() and propagated to the container environment.

                  Screenshots or logs

                  CloudWatch logs from the IC's container (/aws/sagemaker/InferenceComponents/my-orchestrator-ic):

                  /opt/ml/model/code/inference.py:60 in <module>
                  │ ❱ 60 _run_preflight_diagnostics()
                  /opt/ml/model/code/inference.py:38 in _run_preflight_diagnostics
                  │ ❱ 38 │ _pickle_file_integrity_check()
                  /opt/ml/model/code/inference.py:57 in _pickle_file_integrity_check
                  │ ❱ 57 │ perform_integrity_check(buffer=buffer, metadata_path=metadata_path)
                  /opt/conda/lib/python3.12/site-packages/sagemaker/serve/validations/check_integrity.py:26 in perform_integrity_check
                  │ ❱ 26 │ actual_hash_value = compute_hash(buffer=buffer, secret_key=secret_key)
                  AttributeError: 'NoneType' object has no attribute 'encode'
                  

                  The container then fails the ping health check and the IC never reaches InService.

                  System information

                  • SageMaker Python SDK version: sagemaker-serve 1.20.0 (SDK V3)
                  • Framework name: SageMaker Distribution (SMD) container for CustomOrchestrator
                  • Framework version: sagemaker-distribution-prod:3.2.0-cpu
                  • Python version: 3.12
                  • CPU or GPU: GPU (ml.g6.12xlarge endpoint)
                  • Custom Docker image (Y/N): N

                  Additional context

                  There appear to be two sub-issues:

                  1. prepare_for_smd()** has no return statement** — it should return the computed hash (or a generated secret key) so that self.secret_key is set to a real value in model_builder_servers.py L747.
                  2. Version mismatch between SDK and container — The SDK's local check_integrity.py uses plain SHA-256 (hashlib.sha256(buffer).hexdigest()), but the container image (sagemaker-distribution-prod:3.2.0-cpu) still has an older version that uses HMAC with a secret key (hmac.new(secret_key.encode(), msg=buffer, digestmod=hashlib.sha256)). These need to be aligned.

                  Metadata

                  Metadata

                  Assignees

                  No one assigned

                    Type

                    No type

                    Projects

                    No projects

                      Milestone

                      No milestone

                      Relationships

                      None yet

                      Development

                      No branches or pull requests

                      Issue actions

                      , 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' `prepare_for_smd()` missing return value causes `CustomOrchestrator` container health check failure · Issue #6200 · aws/sagemaker-python-sdk · GitHub
                      Skip to content

                      prepare_for_smd() missing return value causes CustomOrchestrator container health check failure #6200

                      Description

                      @lopezfelipe

                      PySDK Version

                      • PySDK V2 (2.x)
                      • PySDK V3 (3.x)

                      Describe the bug

                      When deploying a CustomOrchestrator as an Inference Component — as documented in the Build and deploy AI inference workflows with new enhancements to the Amazon SageMaker Python SDK blog post — the container fails its health check during startup with:

                      AttributeError: 'NoneType' object has no attribute 'encode'
                      

                      The error occurs in the container's _pickle_file_integrity_check() at line 26 of check_integrity.py:

                      actual_hash_value=compute_hash(buffer=buffer, secret_key=secret_key)

                      where secret_key = os.environ.get("SAGEMAKER_SERVE_SECRET_KEY") is None.

                      Root cause:

                      prepare_for_smd() in model_server/smd/prepare.py computes the hash and writes metadata.json, but has no return statement:

                      defprepare_for_smd(model_path, shared_libs, dependencies, inference_spec=None) ->str:
                      ...
                      hash_value=compute_hash(buffer=buffer)
                      withopen(str(code_dir.joinpath("metadata.json")), "wb") asmetadata:
                      metadata.write(_MetaData(hash_value).to_json())
                      # ← No return statement — returns None implicitly

                      In model_builder_servers.py L747:

                      self.secret_key=prepare_for_smd(...) # = None

                      Since self.secret_key is None, the SAGEMAKER_SERVE_SECRET_KEY environment variable is never set on the deployed Model/IC. At runtime, the container's integrity check reads the env var, gets None, and crashes.

                      Additionally, there is a version mismatch between:

                      • The SDK's local check_integrity.py (uses plain SHA-256, no secret key)
                      • The container image's bundled check_integrity.py (uses HMAC with a secret key)

                      To reproduce

                      fromsagemaker.serve.model_builderimportModelBuilder, SchemaBuilderfromsagemaker.serve.spec.inference_baseimportCustomOrchestratorfromsagemaker.core.inference_configimportResourceRequirementsfromsagemaker.core.helper.session_helperimportSession, get_execution_roleclassMyOrchestrator(CustomOrchestrator):
                      def__init__(self, endpoint_name, component_names):
                      super().__init__()
                      self.endpoint_name=endpoint_nameself.component_names=component_namesdefhandle(self, data, context=None):
                      importjsonresponse=self.client.invoke_endpoint(
                      EndpointName=self.endpoint_name,
                      InferenceComponentName=self.component_names[0],
                      Body=dataifisinstance(data, (str, bytes)) elsejson.dumps(data),
                      ContentType="application/json"
                      )
                      returnjson.loads(response["Body"].read())
                      role=get_execution_role()
                      sess=Session()
                      orchestrator=ModelBuilder(
                      inference_spec=MyOrchestrator(
                      endpoint_name="my-existing-endpoint",
                      component_names=["base-ic", "adapter-ic"],
                      ),
                      dependencies={"auto": False, "custom": ["cloudpickle"]},
                      sagemaker_session=sess,
                      role_arn=role,
                      schema_builder=SchemaBuilder(sample_input="Test", sample_output={"generated_text": "test"}),
                      )
                      # Workaround for missing constructor fields (separate issue)orchestrator.resource_requirements=ResourceRequirements(
                      requests={"memory": 4096, "num_accelerators": 1, "copies": 1, "num_cpus": 2}
                      )
                      orchestrator.inference_component_name="my-orchestrator-ic"orchestrator.build()
                      # Verify secret_key is None after build:print(f"secret_key: {orchestrator.secret_key}") # Prints: secret_key: None# Deploy via boto3 (workaround for separate _deploy_for_ic bug):orchestrator_model_name=orchestrator.built_model.model_namesm_client=sess.sagemaker_clientsm_client.create_inference_component(
                      InferenceComponentName="my-orchestrator-ic",
                      EndpointName="my-existing-endpoint",
                      VariantName="AllTraffic",
                      Specification={
                      "ModelName": orchestrator_model_name,
                      "ComputeResourceRequirements": {
                      "NumberOfAcceleratorDevicesRequired": 1,
                      "MinMemoryRequiredInMb": 4096,
                      "NumberOfCpuCoresRequired": 2,
                      },
                      "StartupParameters": {
                      "ModelDataDownloadTimeoutInSeconds": 300,
                      "ContainerStartupHealthCheckTimeoutInSeconds": 300,
                      }
                      },
                      RuntimeConfig={"CopyCount": 1}
                      )
                      # IC fails health check — see CloudWatch logs below

                      Expected behavior

                      The CustomOrchestrator IC should pass its container health check and become InService. The SAGEMAKER_SERVE_SECRET_KEY should be correctly generated during build() and propagated to the container environment.

                      Screenshots or logs

                      CloudWatch logs from the IC's container (/aws/sagemaker/InferenceComponents/my-orchestrator-ic):

                      /opt/ml/model/code/inference.py:60 in <module>
                      │ ❱ 60 _run_preflight_diagnostics()
                      /opt/ml/model/code/inference.py:38 in _run_preflight_diagnostics
                      │ ❱ 38 │ _pickle_file_integrity_check()
                      /opt/ml/model/code/inference.py:57 in _pickle_file_integrity_check
                      │ ❱ 57 │ perform_integrity_check(buffer=buffer, metadata_path=metadata_path)
                      /opt/conda/lib/python3.12/site-packages/sagemaker/serve/validations/check_integrity.py:26 in perform_integrity_check
                      │ ❱ 26 │ actual_hash_value = compute_hash(buffer=buffer, secret_key=secret_key)
                      AttributeError: 'NoneType' object has no attribute 'encode'
                      

                      The container then fails the ping health check and the IC never reaches InService.

                      System information

                      • SageMaker Python SDK version: sagemaker-serve 1.20.0 (SDK V3)
                      • Framework name: SageMaker Distribution (SMD) container for CustomOrchestrator
                      • Framework version: sagemaker-distribution-prod:3.2.0-cpu
                      • Python version: 3.12
                      • CPU or GPU: GPU (ml.g6.12xlarge endpoint)
                      • Custom Docker image (Y/N): N

                      Additional context

                      There appear to be two sub-issues:

                      1. prepare_for_smd()** has no return statement** — it should return the computed hash (or a generated secret key) so that self.secret_key is set to a real value in model_builder_servers.py L747.
                      2. Version mismatch between SDK and container — The SDK's local check_integrity.py uses plain SHA-256 (hashlib.sha256(buffer).hexdigest()), but the container image (sagemaker-distribution-prod:3.2.0-cpu) still has an older version that uses HMAC with a secret key (hmac.new(secret_key.encode(), msg=buffer, digestmod=hashlib.sha256)). These need to be aligned.

                      Metadata

                      Metadata

                      Assignees

                      No one assigned

                        Type

                        No type

                        Projects

                        No projects

                          Milestone

                          No milestone

                          Relationships

                          None yet

                          Development

                          No branches or pull requests

                          Issue actions

                          , 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' `prepare_for_smd()` missing return value causes `CustomOrchestrator` container health check failure · Issue #6200 · aws/sagemaker-python-sdk · GitHub
                          Skip to content

                          prepare_for_smd() missing return value causes CustomOrchestrator container health check failure #6200

                          Description

                          @lopezfelipe

                          PySDK Version

                          • PySDK V2 (2.x)
                          • PySDK V3 (3.x)

                          Describe the bug

                          When deploying a CustomOrchestrator as an Inference Component — as documented in the Build and deploy AI inference workflows with new enhancements to the Amazon SageMaker Python SDK blog post — the container fails its health check during startup with:

                          AttributeError: 'NoneType' object has no attribute 'encode'
                          

                          The error occurs in the container's _pickle_file_integrity_check() at line 26 of check_integrity.py:

                          actual_hash_value=compute_hash(buffer=buffer, secret_key=secret_key)

                          where secret_key = os.environ.get("SAGEMAKER_SERVE_SECRET_KEY") is None.

                          Root cause:

                          prepare_for_smd() in model_server/smd/prepare.py computes the hash and writes metadata.json, but has no return statement:

                          defprepare_for_smd(model_path, shared_libs, dependencies, inference_spec=None) ->str:
                          ...
                          hash_value=compute_hash(buffer=buffer)
                          withopen(str(code_dir.joinpath("metadata.json")), "wb") asmetadata:
                          metadata.write(_MetaData(hash_value).to_json())
                          # ← No return statement — returns None implicitly

                          In model_builder_servers.py L747:

                          self.secret_key=prepare_for_smd(...) # = None

                          Since self.secret_key is None, the SAGEMAKER_SERVE_SECRET_KEY environment variable is never set on the deployed Model/IC. At runtime, the container's integrity check reads the env var, gets None, and crashes.

                          Additionally, there is a version mismatch between:

                          • The SDK's local check_integrity.py (uses plain SHA-256, no secret key)
                          • The container image's bundled check_integrity.py (uses HMAC with a secret key)

                          To reproduce

                          fromsagemaker.serve.model_builderimportModelBuilder, SchemaBuilderfromsagemaker.serve.spec.inference_baseimportCustomOrchestratorfromsagemaker.core.inference_configimportResourceRequirementsfromsagemaker.core.helper.session_helperimportSession, get_execution_roleclassMyOrchestrator(CustomOrchestrator):
                          def__init__(self, endpoint_name, component_names):
                          super().__init__()
                          self.endpoint_name=endpoint_nameself.component_names=component_namesdefhandle(self, data, context=None):
                          importjsonresponse=self.client.invoke_endpoint(
                          EndpointName=self.endpoint_name,
                          InferenceComponentName=self.component_names[0],
                          Body=dataifisinstance(data, (str, bytes)) elsejson.dumps(data),
                          ContentType="application/json"
                          )
                          returnjson.loads(response["Body"].read())
                          role=get_execution_role()
                          sess=Session()
                          orchestrator=ModelBuilder(
                          inference_spec=MyOrchestrator(
                          endpoint_name="my-existing-endpoint",
                          component_names=["base-ic", "adapter-ic"],
                          ),
                          dependencies={"auto": False, "custom": ["cloudpickle"]},
                          sagemaker_session=sess,
                          role_arn=role,
                          schema_builder=SchemaBuilder(sample_input="Test", sample_output={"generated_text": "test"}),
                          )
                          # Workaround for missing constructor fields (separate issue)orchestrator.resource_requirements=ResourceRequirements(
                          requests={"memory": 4096, "num_accelerators": 1, "copies": 1, "num_cpus": 2}
                          )
                          orchestrator.inference_component_name="my-orchestrator-ic"orchestrator.build()
                          # Verify secret_key is None after build:print(f"secret_key: {orchestrator.secret_key}") # Prints: secret_key: None# Deploy via boto3 (workaround for separate _deploy_for_ic bug):orchestrator_model_name=orchestrator.built_model.model_namesm_client=sess.sagemaker_clientsm_client.create_inference_component(
                          InferenceComponentName="my-orchestrator-ic",
                          EndpointName="my-existing-endpoint",
                          VariantName="AllTraffic",
                          Specification={
                          "ModelName": orchestrator_model_name,
                          "ComputeResourceRequirements": {
                          "NumberOfAcceleratorDevicesRequired": 1,
                          "MinMemoryRequiredInMb": 4096,
                          "NumberOfCpuCoresRequired": 2,
                          },
                          "StartupParameters": {
                          "ModelDataDownloadTimeoutInSeconds": 300,
                          "ContainerStartupHealthCheckTimeoutInSeconds": 300,
                          }
                          },
                          RuntimeConfig={"CopyCount": 1}
                          )
                          # IC fails health check — see CloudWatch logs below

                          Expected behavior

                          The CustomOrchestrator IC should pass its container health check and become InService. The SAGEMAKER_SERVE_SECRET_KEY should be correctly generated during build() and propagated to the container environment.

                          Screenshots or logs

                          CloudWatch logs from the IC's container (/aws/sagemaker/InferenceComponents/my-orchestrator-ic):

                          /opt/ml/model/code/inference.py:60 in <module>
                          │ ❱ 60 _run_preflight_diagnostics()
                          /opt/ml/model/code/inference.py:38 in _run_preflight_diagnostics
                          │ ❱ 38 │ _pickle_file_integrity_check()
                          /opt/ml/model/code/inference.py:57 in _pickle_file_integrity_check
                          │ ❱ 57 │ perform_integrity_check(buffer=buffer, metadata_path=metadata_path)
                          /opt/conda/lib/python3.12/site-packages/sagemaker/serve/validations/check_integrity.py:26 in perform_integrity_check
                          │ ❱ 26 │ actual_hash_value = compute_hash(buffer=buffer, secret_key=secret_key)
                          AttributeError: 'NoneType' object has no attribute 'encode'
                          

                          The container then fails the ping health check and the IC never reaches InService.

                          System information

                          • SageMaker Python SDK version: sagemaker-serve 1.20.0 (SDK V3)
                          • Framework name: SageMaker Distribution (SMD) container for CustomOrchestrator
                          • Framework version: sagemaker-distribution-prod:3.2.0-cpu
                          • Python version: 3.12
                          • CPU or GPU: GPU (ml.g6.12xlarge endpoint)
                          • Custom Docker image (Y/N): N

                          Additional context

                          There appear to be two sub-issues:

                          1. prepare_for_smd()** has no return statement** — it should return the computed hash (or a generated secret key) so that self.secret_key is set to a real value in model_builder_servers.py L747.
                          2. Version mismatch between SDK and container — The SDK's local check_integrity.py uses plain SHA-256 (hashlib.sha256(buffer).hexdigest()), but the container image (sagemaker-distribution-prod:3.2.0-cpu) still has an older version that uses HMAC with a secret key (hmac.new(secret_key.encode(), msg=buffer, digestmod=hashlib.sha256)). These need to be aligned.

                          Metadata

                          Metadata

                          Assignees

                          No one assigned

                            Type

                            No type

                            Projects

                            No projects

                              Milestone

                              No milestone

                              Relationships

                              None yet

                              Development

                              No branches or pull requests

                              Issue actions

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

                              prepare_for_smd() missing return value causes CustomOrchestrator container health check failure #6200

                              Description

                              @lopezfelipe

                              PySDK Version

                              • PySDK V2 (2.x)
                              • PySDK V3 (3.x)

                              Describe the bug

                              When deploying a CustomOrchestrator as an Inference Component — as documented in the Build and deploy AI inference workflows with new enhancements to the Amazon SageMaker Python SDK blog post — the container fails its health check during startup with:

                              AttributeError: 'NoneType' object has no attribute 'encode'
                              

                              The error occurs in the container's _pickle_file_integrity_check() at line 26 of check_integrity.py:

                              actual_hash_value=compute_hash(buffer=buffer, secret_key=secret_key)

                              where secret_key = os.environ.get("SAGEMAKER_SERVE_SECRET_KEY") is None.

                              Root cause:

                              prepare_for_smd() in model_server/smd/prepare.py computes the hash and writes metadata.json, but has no return statement:

                              defprepare_for_smd(model_path, shared_libs, dependencies, inference_spec=None) ->str:
                              ...
                              hash_value=compute_hash(buffer=buffer)
                              withopen(str(code_dir.joinpath("metadata.json")), "wb") asmetadata:
                              metadata.write(_MetaData(hash_value).to_json())
                              # ← No return statement — returns None implicitly

                              In model_builder_servers.py L747:

                              self.secret_key=prepare_for_smd(...) # = None

                              Since self.secret_key is None, the SAGEMAKER_SERVE_SECRET_KEY environment variable is never set on the deployed Model/IC. At runtime, the container's integrity check reads the env var, gets None, and crashes.

                              Additionally, there is a version mismatch between:

                              • The SDK's local check_integrity.py (uses plain SHA-256, no secret key)
                              • The container image's bundled check_integrity.py (uses HMAC with a secret key)

                              To reproduce

                              fromsagemaker.serve.model_builderimportModelBuilder, SchemaBuilderfromsagemaker.serve.spec.inference_baseimportCustomOrchestratorfromsagemaker.core.inference_configimportResourceRequirementsfromsagemaker.core.helper.session_helperimportSession, get_execution_roleclassMyOrchestrator(CustomOrchestrator):
                              def__init__(self, endpoint_name, component_names):
                              super().__init__()
                              self.endpoint_name=endpoint_nameself.component_names=component_namesdefhandle(self, data, context=None):
                              importjsonresponse=self.client.invoke_endpoint(
                              EndpointName=self.endpoint_name,
                              InferenceComponentName=self.component_names[0],
                              Body=dataifisinstance(data, (str, bytes)) elsejson.dumps(data),
                              ContentType="application/json"
                              )
                              returnjson.loads(response["Body"].read())
                              role=get_execution_role()
                              sess=Session()
                              orchestrator=ModelBuilder(
                              inference_spec=MyOrchestrator(
                              endpoint_name="my-existing-endpoint",
                              component_names=["base-ic", "adapter-ic"],
                              ),
                              dependencies={"auto": False, "custom": ["cloudpickle"]},
                              sagemaker_session=sess,
                              role_arn=role,
                              schema_builder=SchemaBuilder(sample_input="Test", sample_output={"generated_text": "test"}),
                              )
                              # Workaround for missing constructor fields (separate issue)orchestrator.resource_requirements=ResourceRequirements(
                              requests={"memory": 4096, "num_accelerators": 1, "copies": 1, "num_cpus": 2}
                              )
                              orchestrator.inference_component_name="my-orchestrator-ic"orchestrator.build()
                              # Verify secret_key is None after build:print(f"secret_key: {orchestrator.secret_key}") # Prints: secret_key: None# Deploy via boto3 (workaround for separate _deploy_for_ic bug):orchestrator_model_name=orchestrator.built_model.model_namesm_client=sess.sagemaker_clientsm_client.create_inference_component(
                              InferenceComponentName="my-orchestrator-ic",
                              EndpointName="my-existing-endpoint",
                              VariantName="AllTraffic",
                              Specification={
                              "ModelName": orchestrator_model_name,
                              "ComputeResourceRequirements": {
                              "NumberOfAcceleratorDevicesRequired": 1,
                              "MinMemoryRequiredInMb": 4096,
                              "NumberOfCpuCoresRequired": 2,
                              },
                              "StartupParameters": {
                              "ModelDataDownloadTimeoutInSeconds": 300,
                              "ContainerStartupHealthCheckTimeoutInSeconds": 300,
                              }
                              },
                              RuntimeConfig={"CopyCount": 1}
                              )
                              # IC fails health check — see CloudWatch logs below

                              Expected behavior

                              The CustomOrchestrator IC should pass its container health check and become InService. The SAGEMAKER_SERVE_SECRET_KEY should be correctly generated during build() and propagated to the container environment.

                              Screenshots or logs

                              CloudWatch logs from the IC's container (/aws/sagemaker/InferenceComponents/my-orchestrator-ic):

                              /opt/ml/model/code/inference.py:60 in <module>
                              │ ❱ 60 _run_preflight_diagnostics()
                              /opt/ml/model/code/inference.py:38 in _run_preflight_diagnostics
                              │ ❱ 38 │ _pickle_file_integrity_check()
                              /opt/ml/model/code/inference.py:57 in _pickle_file_integrity_check
                              │ ❱ 57 │ perform_integrity_check(buffer=buffer, metadata_path=metadata_path)
                              /opt/conda/lib/python3.12/site-packages/sagemaker/serve/validations/check_integrity.py:26 in perform_integrity_check
                              │ ❱ 26 │ actual_hash_value = compute_hash(buffer=buffer, secret_key=secret_key)
                              AttributeError: 'NoneType' object has no attribute 'encode'
                              

                              The container then fails the ping health check and the IC never reaches InService.

                              System information

                              • SageMaker Python SDK version: sagemaker-serve 1.20.0 (SDK V3)
                              • Framework name: SageMaker Distribution (SMD) container for CustomOrchestrator
                              • Framework version: sagemaker-distribution-prod:3.2.0-cpu
                              • Python version: 3.12
                              • CPU or GPU: GPU (ml.g6.12xlarge endpoint)
                              • Custom Docker image (Y/N): N

                              Additional context

                              There appear to be two sub-issues:

                              1. prepare_for_smd()** has no return statement** — it should return the computed hash (or a generated secret key) so that self.secret_key is set to a real value in model_builder_servers.py L747.
                              2. Version mismatch between SDK and container — The SDK's local check_integrity.py uses plain SHA-256 (hashlib.sha256(buffer).hexdigest()), but the container image (sagemaker-distribution-prod:3.2.0-cpu) still has an older version that uses HMAC with a secret key (hmac.new(secret_key.encode(), msg=buffer, digestmod=hashlib.sha256)). These need to be aligned.

                              Metadata

                              Metadata

                              Assignees

                              No one assigned

                                Type

                                No type

                                Projects

                                No projects

                                  Milestone

                                  No milestone

                                  Relationships

                                  None yet

                                  Development

                                  No branches or pull requests

                                  Issue actions