fix(storage): don't clobber the global fsspec registry on import - #1440
Open
cosmicBboy wants to merge 1 commit into
Open
fix(storage): don't clobber the global fsspec registry on import#1440cosmicBboy wants to merge 1 commit into
cosmicBboy wants to merge 1 commit into
Conversation
Importing `flyte` (v2) inside a process that also runs flytekit (v1) broke
all of flytekit's object-store I/O: `flyte.storage._storage` unconditionally
ran `obstore.fsspec.register(["s3", "gs", "abfs", "abfss"], ...)` at import
time, replacing s3fs/gcsfs/adlfs in the global fsspec registry. flytekit then
called `fsspec.filesystem("s3", cache_regions=True, ...)` and obstore rejected
the s3fs-only kwargs ("Configuration key: 'cache_regions' is not valid for
store 'S3'"), failing every output upload and masking the real task error.
Two-part fix:
1. flyte's own I/O is now registry-independent: for obstore-supported
protocols, `get_underlying_filesystem` instantiates a flyte-owned
per-protocol subclass of `obstore.fsspec.FsspecStore` directly (mirroring
what `obstore.fsspec.register` builds, including instance caching via
fsspec's `_Cached` metaclass) instead of resolving through the registry.
2. Global registration is now non-destructive gap-filling: obstore is only
registered for a protocol when nothing else is registered and no other
implementation (e.g. s3fs) is importable, so pure-v2 images keep working
`s3://` paths for pandas/pyarrow while hybrid v1/v2 processes keep
flytekit's filesystems intact regardless of import order.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Symptom
In a hybrid v1/v2 setup — a flytekit (v1) task that imports
flyte(v2) to remotely launch v2 tasks — merely importingflytebreaks all of flytekit's S3/GCS/Azure I/O in that process. Every output upload fails with:surfacing as a
FlyteUploadDataException/ SYSTEM error that also masks the task's real error (the failed task can't even upload its error document).Root cause
src/flyte/storage/_storage.pyran this at import time:obstore.fsspec.registerregisters withclobber=True, replacing the global fsspec registry entries fors3,gs,abfs, andabfss. flytekit'sdata_persistence.pyresolves filesystems through that registry (fsspec.filesystem("s3", cache_regions=True, ...)with s3fs-specific kwargs), and obstore's store rejects those kwargs.Fix (two parts)
flyte's own I/O no longer depends on the global registry. For obstore-supported protocols (
s3,gs,abfs,abfss),get_underlying_filesystem()now instantiates a flyte-owned per-protocol subclass ofobstore.fsspec.FsspecStoredirectly (_obstore_filesystem_class, mirroring exactly whatobstore.fsspec.register(..., asynchronous=True)builds). fsspec's_Cachedmetaclass still applies to direct instantiation, so instance caching is preserved, and the obstore bypasses (_split_path/_construct_store) and anonymous-access fallback keep getting obstore-backed instances. Other protocols still go throughfsspec.filesystem(...).Global registration is now non-destructive gap-filling.
_register_obstore_for_missing_protocols()registers obstore for a protocol only if (a) nothing is already registered for it and (b) no other implementation is importable (fsspec.get_filesystem_classraisesImportError). The importability probe matters because fsspec resolvesknown_implementationslazily — in a hybrid image the registry can be empty atimport flytetime even though s3fs is installed, so a registry-only check would still clobber. This keeps today's behavior in pure-v2 images (no s3fs installed → obstore registered so pandas/pyarrows3://paths keep working) while never stomping on flytekit's s3fs/gcsfs/adlfs, regardless of import order.The
flyteprotocol registration (FlyteFS) is unchanged.fsspec.filesystem(protocol)uses elsewhere in the SDK (models.py,io/_file.py,_remote_fs.py) only readfs.sepfor path joining and work with whichever implementation resolves, so they are intentionally untouched.Testing
New
tests/internal/storage/test_fsspec_registry.py:fsspec.filesystem("s3")still resolves to itget_underlying_filesystem("s3")returns an obstore-backed FS (_split_path/_construct_store) even when s3fs-style owns the registryfsspec.filesystem("s3", cache_regions=True)reaches the registered class instead of obstoreobstore.fsspec.register(protocol/asynchronous attrs, class + instance caching)Also verified end-to-end in fresh subprocesses for both environments (pure-v2: obstore gets registered for all four protocols; hybrid: pre-registered s3fs-style survives and accepts
cache_regions=Truewhile flyte's own I/O stays obstore-backed). Existing storage/io/init suites pass (pytest -k "not integration and not sandbox"), plusruff check,ruff format --check, andmypyon the touched module.🤖 Generated with Claude Code