Skip to content

Fix ModelVersion.load in Container Runtime notebooks: download via session.file.get - #241

Open
haoweiyu-kumo wants to merge 1 commit into
snowflakedb:mainfrom
haoweiyu-kumo:fix/get-file-use-fileoperation
Open

Fix ModelVersion.load in Container Runtime notebooks: download via session.file.get#241
haoweiyu-kumo wants to merge 1 commit into
snowflakedb:mainfrom
haoweiyu-kumo:fix/get-file-use-fileoperation

Conversation

@haoweiyu-kumo

Copy link
Copy Markdown

Problem

ModelVersion.load() fails inside a Snowflake Container Runtime notebook with:

ProgrammingError: 000710 (02000): Result for query <id> has expired

The notebook runtime monkeypatches DataFrame.collect() into a cancellable async job (snowflake_notebook_utils.session_bootstrap), which re-fetches results via result_scan(<sfqid>). ModelVersionSQLClient.get_file downloads model files in its non-stored-procedure branch by running a raw GET snow://model/... file://... through session.sql(...).collect(). A GET produces no result set that result_scan can replay, so the async re-fetch returns "expired" and load() blows up.

Notably, upload works (log_model) because it uses session.file.put (file_utils.upload_directory_to_stage), which goes through the connector file-transfer path rather than collect(). The download path was asymmetric.

Fix

Download via session.file.get — the FileOperation API symmetric to the session.file.put used when logging a model. It uses the connector file-transfer path and does not depend on collect(), so it is unaffected by the notebook's cancellable-collect patch. snow:// is already an accepted GET prefix (SNOWURL_PREFIX), so the registry stage URL works unchanged.

The stored-procedure branch (which already uses the low-level cursor._download) is untouched. The previous has_dimensions(expected_rows=1) assertion is preserved as an explicit check that exactly one file was downloaded.

Impact

  • Fixes ModelVersion.load() / model download in Container Runtime notebooks.
  • Makes model upload and download both go through the FileOperation API.
  • No behavior change in stored procedures or warehouse contexts.

ModelVersionSQLClient.get_file's non-stored-procedure branch runs a raw
`GET snow://model/... file://...` through DataFrame.collect(). In
environments that wrap collect() -- e.g. Snowflake Container Runtime
notebooks patch it into a cancellable async job -- a GET has no result
set that can be replayed via result_scan, so ModelVersion.load() fails
with `ProgrammingError 000710 (02000): Result for query <id> has
expired`.

Use session.file.get (the FileOperation API that mirrors the
session.file.put used when logging a model); it goes through the
connector file-transfer path and does not depend on collect(). This also
makes upload/download symmetric.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@haoweiyu-kumo
haoweiyu-kumo force-pushed the fix/get-file-use-fileoperation branch from 7090bef to c762b41 Compare July 28, 2026 18:12
@sfc-gh-thoyt

Copy link
Copy Markdown
Collaborator

Thanks for the PR @haoweiyu-kumo . We will incorporate this fix into an upcoming release.

@sfc-gh-thoyt

Copy link
Copy Markdown
Collaborator

@haoweiyu-kumo Out of curiosity, what is the reason for using mv.load in a container runtime environment? Are you trying to do inference in the container runtime instead of via the model registry (via mv.run or in SPCS), or is there some other reason?

@haoweiyu-kumo

Copy link
Copy Markdown
Author

Yeah, I am trying to do batch inference in side notebook. I can just launch a dedicated SPCS job ( via mv.run_batch ). I am not sure if that's the "standard" way of DS doing batch prediction during development cycle.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants