Pitfalls¶
Technical gotchas for extension developers and distribution builders. If you're a user looking for help with a broken stack, see the helmfile2compose troubleshooting guide.
Null-safe YAML access¶
Python's dict.get("key", default) returns default only when the key is absent. When the key exists with an explicit None value — common in Helm charts with conditional {{ if }} blocks — .get() returns None, not the default.
# WRONG — returns None when key exists with null value
annotations = manifest.get("metadata", {}).get("annotations", {})
# RIGHT — coalesces None to empty dict
annotations = manifest.get("metadata", {}).get("annotations") or {}
This applies to any field that Helm may render as null: annotations, ports, initContainers, securityContext, data, stringData, rules, selector. Use or {} / or [] for any .get() on a YAML field that could be explicitly null.
See The null that devours silently for the full history (v2.3.1 fixed 30+ instances).
sys.modules and module identity¶
When a distribution runs as helmfile2compose.py, Python sees the module as __main__. Extensions that from dekube import ConverterResult would create a separate module namespace — dekube.ConverterResult ≠ __main__.ConverterResult. This breaks isinstance checks and mutable registry state.
The build system injects a one-liner to fix this:
Consequences for extension authors:
- Prefer duck typing over
isinstance. Usegetattr(result, 'services', None)instead ofisinstance(result, ProviderResult). - Import from
dekube, not from internal submodules (dekube.pacts.types). The flat file has no submodules. - The legacy
h2cshim still works but new extensions should usedekube.
See Build system — The sys.modules fix for the full explanation.
Build system gotchas¶
These affect distribution builders, not extension authors.
- Artifact shadowing — a
dekube.pybuild artifact in the dev directory shadows thesrc/dekube/package. Delete it before runningPYTHONPATH=src python -m dekube. - Module order —
CORE_MODULESinbuild.pymust be topologically sorted. Wrong order →NameErroron--help(the smoke test catches this). - Third-party detection — the import sorter checks
module == "yaml". If a new third-party dep is added, update this check. _auto_register()skips_-prefixed names — naming a class_MyConverterprevents registration. New base classes must be added to_BASE_CLASSES.- Duplicate kind = fatal — two classes claiming the same
kindcausessys.exit(1). Intentional — silent conflicts are worse.
See Build system — Gotchas for details on each.
Docker/Compose gotchas¶
Runtime limitations of Docker Compose itself, not the conversion engine.
- Large port ranges — K8s with
hostNetworkhandles thousands of ports natively. Docker creates one iptables/pf rule per port, so a range like 50000-60000 (e.g. WebRTC) will kill your network stack. Reduce the range in your compose environment values. - hostNetwork — every exposed port must be mapped explicitly in compose. K8s pods can bind directly; compose services cannot.
- S3 virtual-hosted style — AWS SDKs default to virtual-hosted bucket URLs (
bucket-name.s3:9000). Compose DNS can't resolve dotted hostnames. Configure path-style access and use areplacementif needed.