Building multiple charms simultaneously can cause caching errors
Metadata
Current evaluation
Closed. Charmcraft will detect parallel builds and disable caching with a warning to prevent race conditions and zipfile errors during simultaneous charm builds.
Suggested action: —
No scores available.
Issue body
### Bug Description
Using `charmcraft` from `latest/edge` in GH runners results in istio charms failing to be built. More specifically, this results in the [following zipfile bug](https://github.com/canonical/bundle-kubeflow/issues/1005). This used to happen intermittently but with `latest/edge` it happens 90% of the time ([example](https://github.com/canonical/istio-operators/actions/runs/10246771376/job/28639271698?pr=498) where the CI has been re-run 7 times).
Note that, as mentioned in this https://github.com/canonical/bundle-kubeflow/issues/1005#issuecomment-2289148457:
>Building the charm in a fresh LXC container using charmcraft both from `latest/edge` and `latest/candidate` is successful.
A pointer by @lengau was that it could be an issue with the GH runner space, but it was attempted to free up some space before running the tests https://github.com/canonical/istio-operators/pull/532 (44G up from 21G), but the issue persisted.
Apart from logs pasted below, here's from another run for [reference](https://pastebin.canonical.com/p/jbtCsfRrBF/).
### To Reproduce
Rerun the CI in this draft PR https://github.com/canonical/istio-operators/pull/506 (where charmcraft form `latest/edge` is being used) compared to when [using latest/candidate](https://github.com/canonical/istio-operators/pull/510).
### Environment
Microk8s 1.25,1.26
Juju 3.4.5
Some charmcraft versions that have been failing:
* charmcraft (edge) 3.1.2.post11+g0d3b2713 from Canonical** installed
* charmcraft (edge) 3.1.2.post84+g3f0dbc6c from Canonical** installed
But the charms are built with 3.1.2.
### charmcraft.yaml
```shell
type: charm
bases:
- build-on:
- name: "ubuntu"
channel: "20.04"
run-on:
- name: "ubuntu"
channel: "20.04"
parts:
charm:
charm-python-packages: [setuptools, pip]
build-packages: [git, rustc, cargo, libffi-dev, libssl-dev, pkg-config]
istioctl:
plugin: dump
source: https://github.com/istio/istio/releases/download/1.17.3/istioctl-1.17.3-linux-amd64.tar.gz
source-type: tar
---
type: charm
bases:
- build-on:
- name: 'ubuntu'
channel: '20.04'
run-on:
- name: 'ubuntu'
channel: '20.04'
parts:
charm:
charm-python-packages: [setuptools, pip]
```
### Relevant log output
```shell
:: :: Successfully built setuptools wheel
:: :: Installing collected packages: setuptools, wheel
:: :: ERROR: Exception:
:: :: Traceback (most recent call last):
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py", line 186, in _main
:: :: status = self.run(options, args)
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/commands/install.py", line 421, in run
:: :: installed = install_given_reqs(
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/req/__init__.py", line 67, in install_given_reqs
:: :: requirement.install(
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/req/req_install.py", line 809, in install
:: :: install_wheel(
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/operations/install/wheel.py", line 606, in install_wheel
:: :: unpack_file(wheel_path, unpacked_dir.path)
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/utils/unpacking.py", line 249, in unpack_file
:: :: unzip_file(
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/utils/unpacking.py", line 139, in unzip_file
:: :: shutil.copyfileobj(fp, destfp)
:: :: File "/usr/lib/python3.8/shutil.py", line 205, in copyfileobj
:: :: buf = fsrc_read(length)
:: :: File "/usr/lib/python3.8/zipfile.py", line 940, in read
:: :: data = self._read1(n)
:: :: File "/usr/lib/python3.8/zipfile.py", line 1008, in _read1
:: :: data += self._read2(n - len(data))
:: :: File "/usr/lib/python3.8/zipfile.py", line 1043, in _read2
:: :: raise EOFError
:: :: EOFError
:: :: ----------------------------------------
:: :: ERROR: Command errored out with exit status 2: /root/parts/charm/build/staging-venv/bin/python3 /root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip install --ignore-installed --no-user --prefix /tmp/pip-build-env-_x_j7juu/overlay --no-warn-script-location --no-binary anyio,attrs,certifi,charmed-kubeflow-chisme,charset-normalizer,deepdiff,exceptiongroup,h11,httpcore,httpx,idna,importlib-resources,jsonschema,lightkube,lightkube-models,markupsafe,ops,ordered-set,pip,pkgutil-resolve-name,pyrsistent,pyyaml,requests,ruamel-yaml,ruamel-yaml-clib,serialized-data-interface,setuptools,sniffio,tenacity,urllib3,websocket-client,wheel,zipp --only-binary :none: -i https://pypi.org/simple -- 'setuptools>=40.8.0' wheel Check the logs for full command output.
:: WARNING: Initial package installation failed. Falling back to older method, which may leave your charm in an un-runnable state.
:: Running external command ['/root/parts/charm/build/staging-venv/bin/pip', 'install', '--upgrade', 'jinja2']
:: :: Collecting jinja2
:: :: Downloading jinja2-3.1.4-py3-none-any.whl (133 kB)
:: :: Collecting MarkupSafe>=2.0
:: :: Downloading MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (26 kB)
:: :: Installing collected packages: MarkupSafe, jinja2
:: :: Successfully installed MarkupSafe-2.1.5 jinja2-3.1.4
:: Running external command ['/root/parts/charm/build/staging-venv/bin/pip', 'install', '--upgrade', '--no-binary', ':all:', 'wheel', 'setuptools', 'pip']
:: :: Collecting wheel
:: :: Using cached wheel-0.43.0.tar.gz (99 kB)
:: :: Installing build dependencies: started
:: :: Installing build dependencies: finished with status 'done'
:: :: Getting requirements to build wheel: started
:: :: Getting requirements to build wheel: finished with status 'done'
:: :: Preparing wheel metadata: started
:: :: Preparing wheel metadata: finished with status 'done'
:: :: Collecting setuptools
:: :: Using cached setuptools-69.5.1.tar.gz (2.3 MB)
:: :: Getting requirements to build wheel: started
:: :: Getting requirements to build wheel: finished with status 'done'
:: :: Installing backend dependencies: started
:: :: Installing backend dependencies: finished with status 'done'
:: :: Preparing wheel metadata: started
:: :: Preparing wheel metadata: finished with status 'done'
:: :: Collecting pip
:: :: Downloading pip-24.0.tar.gz (2.1 MB)
:: :: Installing build dependencies: started
:: :: Installing build dependencies: finished with status 'done'
:: :: Getting requirements to build wheel: started
:: :: Getting requirements to build wheel: finished with status 'done'
:: :: Preparing wheel metadata: started
:: :: Preparing wheel metadata: finished with status 'done'
:: :: Building wheels for collected packages: wheel, setuptools, pip
:: :: Building wheel for wheel (PEP 517): started
:: :: Building wheel for wheel (PEP 517): finished with status 'done'
:: :: Created wheel for wheel: filename=wheel-0.43.0-py3-none-any.whl size=65775 sha256=55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81
:: :: Stored in directory: /root/.cache/pip/wheels/d4/a3/b2/6faade3bb04cd720bb432a6c21ec7baa2542801334a4d47a66
:: :: Building wheel for setuptools (PEP 517): started
:: :: Building wheel for setuptools (PEP 517): finished with status 'done'
:: :: Created wheel for setuptools: filename=setuptools-69.5.1-py3-none-any.whl size=894566 sha256=075e940cfa3659352ca81f87fabf8b4b75ccdbb5f99f2a71a4f77df1b6707fbc
:: :: Stored in directory: /root/.cache/pip/wheels/57/b6/41/311c955c1ca3eed447666adf5ca9680ddcdd11dc785a746bf6
:: :: Building wheel for pip (PEP 517): started
:: :: Building wheel for pip (PEP 517): finished with status 'done'
:: :: Created wheel for pip: filename=pip-24.0-py3-none-any.whl size=2110223 sha256=7176c5cddbc465dc78dddac6545a4635901a7c9a08a959f4f3bbb3ca0bee944a
:: :: Stored in directory: /root/.cache/pip/wheels/c1/d6/d4/2f7765d82b17d8c25425875b2dce5af9f22746668c3add50f6
:: :: Successfully built wheel setuptools pip
:: :: Installing collected packages: wheel, setuptools, pip
:: :: Attempting uninstall: setuptools
:: :: Found existing installation: setuptools 44.0.0
:: :: Uninstalling setuptools-44.0.0:
:: :: Successfully uninstalled setuptools-44.0.0
:: :: Attempting uninstall: pip
:: :: Found existing installation: pip 20.0.2
:: :: Uninstalling pip-20.0.2:
:: :: Successfully uninstalled pip-20.0.2
:: :: Successfully installed pip-24.0 setuptools-69.5.1 wheel-0.43.0
:: Running external command ['/root/parts/charm/build/staging-venv/bin/pip', 'install', '--upgrade', '--no-binary', ':all:', '--requirement=requirements.txt']
:: :: Collecting anyio==3.7.1 (from -r requirements.txt (line 7))
:: :: Downloading anyio-3.7.1.tar.gz (142 kB)
:: :: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 142.9/142.9 kB 3.9 MB/s eta 0:00:00
:: :: Installing build dependencies: started
:: :: Installing build dependencies: finished with status 'done'
:: :: Getting requirements to build wheel: started
:: :: Getting requirements to build wheel: finished with status 'done'
:: :: Installing backend dependencies: started
:: :: Installing backend dependencies: finished with status 'done'
:: :: Preparing metadata (pyproject.toml): started
:: :: Preparing metadata (pyproject.toml): finished with status 'done'
:: :: Collecting attrs==23.1.0 (from -r requirements.txt (line 9))
:: :: Downloading attrs-23.1.0.tar.gz (212 kB)
:: :: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 212.9/212.9 kB 29.5 MB/s eta 0:00:00
:: :: Installing build dependencies: started
:: :: Installing build dependencies: finished with status 'error'
:: :: error: subprocess-exited-with-error
:: ::
:: :: × pip subprocess to install build dependencies did not run successfully.
:: :: │ exit code: 1
:: :: ╰─> [103 lines of output]
:: :: Collecting hatchling
:: :: Downloading hatchling-1.24.2.tar.gz (63 kB)
:: :: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 64.0/64.0 kB 2.0 MB/s eta 0:00:00
:: :: Getting requirements to build wheel: started
:: :: Getting requirements to build wheel: finished with status 'done'
:: :: Installing backend dependencies: started
:: :: Installing backend dependencies: finished with status 'error'
:: :: error: subprocess-exited-with-error
:: ::
:: :: × pip subprocess to install backend dependencies did not run successfully.
:: :: │ exit code: 1
:: :: ╰─> [81 lines of output]
:: :: Collecting packaging>=23.2
:: :: Using cached packaging-24.0-py3-none-any.whl
:: :: Collecting pathspec>=0.10.1
:: :: Downloading pathspec-0.12.1.tar.gz (51 kB)
:: :: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 51.0/51.0 kB 895.3 kB/s eta 0:00:00
:: :: Installing build dependencies: started
:: :: Installing build dependencies: finished with status 'done'
:: :: Getting requirements to build wheel: started
:: :: Getting requirements to build wheel: finished with status 'done'
:: :: Preparing metadata (pyproject.toml): started
:: :: Preparing metadata (pyproject.toml): finished with status 'done'
:: :: Collecting trove-classifiers
:: :: Downloading trove-classifiers-2024.4.10.tar.gz (16 kB)
:: :: Installing build dependencies: started
:: :: Installing build dependencies: finished with status 'done'
:: :: Getting requirements to build wheel: started
:: :: Getting requirements to build wheel: finished with status 'done'
:: :: Installing backend dependencies: started
:: :: Installing backend dependencies: finished with status 'done'
:: :: Preparing metadata (pyproject.toml): started
:: :: Preparing metadata (pyproject.toml): finished with status 'done'
:: :: Collecting tomli>=1.2.2
:: :: Using cached tomli-2.0.1-py3-none-any.whl
:: :: Collecting pluggy>=1.0.0
:: :: Downloading pluggy-1.5.0.tar.gz (67 kB)
:: :: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 68.0/68.0 kB 3.5 MB/s eta 0:00:00
:: :: Installing build dependencies: started
:: :: Installing build dependencies: finished with status 'error'
:: :: error: subprocess-exited-with-error
:: ::
:: :: × pip subprocess to install build dependencies did not run successfully.
:: :: │ exit code: 2
:: :: ╰─> [38 lines of output]
:: :: Collecting setuptools>=45.0
:: :: Using cached setuptools-69.5.1-py3-none-any.whl
:: :: Collecting setuptools-scm>=6.2.3 (from setuptools-scm[toml]>=6.2.3)
:: :: Using cached setuptools_scm-8.1.0-py3-none-any.whl
:: :: Collecting packaging>=20 (from setuptools-scm>=6.2.3->setuptools-scm[toml]>=6.2.3)
:: :: Using cached packaging-24.0-py3-none-any.whl
:: :: Collecting typing-extensions (from setuptools-scm>=6.2.3->setuptools-scm[toml]>=6.2.3)
:: :: Using cached typing_extensions-4.11.0-py3-none-any.whl
:: :: Collecting tomli>=1 (from setuptools-scm>=6.2.3->setuptools-scm[toml]>=6.2.3)
:: :: Using cached tomli-2.0.1-py3-none-any.whl
:: :: Installing collected packages: typing-extensions, tomli, setuptools, packaging, setuptools-scm
:: :: ERROR: Exception:
:: :: Traceback (most recent call last):
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py", line 180, in exc_logging_wrapper
:: :: status = run_func(*args)
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/cli/req_command.py", line 245, in wrapper
:: :: return func(self, options, args)
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/commands/install.py", line 452, in run
:: :: installed = install_given_reqs(
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/req/__init__.py", line 72, in install_given_reqs
:: :: requirement.install(
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/req/req_install.py", line 856, in install
:: :: install_wheel(
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/operations/install/wheel.py", line 725, in install_wheel
:: :: _install_wheel(
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/operations/install/wheel.py", line 585, in _install_wheel
:: :: file.save()
:: :: File "/root/parts/charm/build/staging-venv/lib/python3.8/site-packages/pip/_internal/operations/install/wheel.py", line 384, in save
:: :: shutil.copyfileobj(f, dest)
:: :: File "/usr/lib/python3.8/shutil.py", line 205, in copyfileobj
:: :: buf = fsrc_read(length)
:: :: File "/usr/lib/python3.8/zipfile.py", line 940, in read
:: :: data = self._read1(n)
:: :: File "/usr/lib/python3.8/zipfile.py", line 1008, in _read1
:: :: data += self._read2(n - len(data))
:: :: File "/usr/lib/python3.8/zipfile.py", line 1043, in _read2
:: :: raise EOFError
:: :: EOFError
:: :: [end of output]
:: ::
:: :: note: This error originates from a subprocess, and is likely not a problem with pip.
:: :: error: subprocess-exited-with-error
:: ::
:: :: × pip subprocess to install build dependencies did not run successfully.
:: :: │ exit code: 2
:: :: ╰─> See above for output.
:: ::
:: :: note: This error originates from a subprocess, and is likely not a problem with pip.
:: :: [end of output]
:: ::
:: :: note: This error originates from a subprocess, and is likely not a problem with pip.
:: :: error: subprocess-exited-with-error
:: ::
:: :: × pip subprocess to install backend dependencies did not run successfully.
:: :: │ exit code: 1
:: :: ╰─> See above for output.
:: ::
:: :: note: This error originates from a subprocess, and is likely not a problem with pip.
:: :: [end of output]
:: ::
:: :: note: This error originates from a subprocess, and is likely not a problem with pip.
:: :: error: subprocess-exited-with-error
:: ::
:: :: × pip subprocess to install build dependencies did not run successfully.
:: :: │ exit code: 1
:: :: ╰─> See above for output.
:: ::
:: :: note: This error originates from a subprocess, and is likely not a problem with pip.
:: Traceback (most recent call last):
:: File "/snap/charmcraft/3454/lib/python3.10/site-packages/charmcraft/charm_builder.py", line 260, in _install_dependencies
:: _process_run(
:: File "/snap/charmcraft/3454/lib/python3.10/site-packages/charmcraft/charm_builder.py", line 408, in _process_run
:: raise RuntimeError(f"Subprocess command {cmd} execution failed with retcode {retcode}")
:: RuntimeError: Subprocess command ['/root/parts/charm/build/staging-venv/bin/pip', 'install', '--no-binary=anyio,attrs,certifi,charmed-kubeflow-chisme,charset-normalizer,deepdiff,exceptiongroup,h11,httpcore,httpx,idna,importlib-resources,jsonschema,lightkube,lightkube-models,markupsafe,ops,ordered-set,pip,pkgutil-resolve-name,pyrsistent,pyyaml,requests,ruamel-yaml,ruamel-yaml-clib,serialized-data-interface,setuptools,sniffio,tenacity,urllib3,websocket-client,wheel,zipp', '--requirement=requirements.txt', 'pip', 'setuptools', 'wheel'] execution failed with retcode 1
::
:: During handling of the above exception, another exception occurred:
::
:: Traceback (most recent call last):
:: File "/snap/charmcraft/3454/lib/python3.10/site-packages/charmcraft/charm_builder.py", line 477, in <module>
:: main()
:: File "/snap/charmcraft/3454/lib/python3.10/site-packages/charmcraft/charm_builder.py", line 472, in main
:: builder.build_charm()
:: File "/snap/charmcraft/3454/lib/python3.10/site-packages/charmcraft/charm_builder.py", line 101, in build_charm
:: self.handle_dependencies()
:: File "/snap/charmcraft/3454/lib/python3.10/site-packages/charmcraft/charm_builder.py", line 354, in handle_dependencies
:: self._install_dependencies(staging_venv_dir)
:: File "/snap/charmcraft/3454/lib/python3.10/site-packages/charmcraft/instrum.py", line 152, in _f
:: return func(*args, **kwargs)
:: File "/snap/charmcraft/3454/lib/python3.10/site-packages/charmcraft/charm_builder.py", line 289, in _install_dependencies
:: _process_run(cmd)
:: File "/snap/charmcraft/3454/lib/python3.10/site-packages/charmcraft/charm_builder.py", line 408, in _process_run
:: raise RuntimeError(f"Subprocess command {cmd} execution failed with retcode {retcode}")
:: RuntimeError: Subprocess command ['/root/parts/charm/build/staging-venv/bin/pip', 'install', '--upgrade', '--no-binary', ':all:', '--requirement=requirements.txt'] execution failed with retcode 1
Parts processing error: Failed to run the build script for part 'charm'.
Failed to build charm for bases index '0'.
Full execution log: '/home/runner/.local/state/charmcraft/log/charmcraft-20240509-152917.976217.log'
```
Evaluation history
| Date | Model | Scores | Action | Summary |
|---|---|---|---|---|
| qwen3.6-35b-a3b-mtp-q6 | — | — | Closed. Charmcraft will detect parallel builds and disable caching with a warning to prevent race conditions and zipfile errors during simultaneous charm builds. | |
| qwen/qwen3.6-35b-a3b | — | — | Fixed. The team resolved the parallel build caching conflicts by implementing a detection mechanism that automatically disables the cache and logs a warning when simultaneous charm builds are detected. | |
| qwen/qwen3.6-35b-a3b | — | — | Closed. The team will detect parallel charm builds and automatically disable the cache with a warning to prevent EOFError conflicts from simultaneous wheel downloads. | |
| qwen/qwen3.6-35b-a3b | — | — | Charmcraft will detect parallel builds and automatically disable caching with a warning to prevent race conditions on shared wheel files, resolving the EOFError conflicts caused by simultaneous charm builds. | |
| qwen3.6-35b-a3b-mtp-q6 | — | — | Fixed concurrent build cache corruption by detecting parallel builds and disabling caching with a warning to prevent race conditions, eliminating the need for complex workarounds. | |
| qwen3.6-35b-a3b-mtp-q6 | — | — | Resolved. Charmcraft will detect parallel builds and automatically disable caching to prevent race conditions with shared wheel files, logging a warning instead. This fixes the EOFError in concurrent CI environments. |
Update history
No update history recorded yet.
Related issues
| Issue | Project | State | Summary | Similarity |
|---|---|---|---|---|
| #249 `charmcraft build` will let you build a charm that won't deploy | charmcraft | closed | Closed and superseded by issue #27. The charmcraft build validation gap was consolidated into a tracking issue for implementing build-time sanity checks on config.yaml and actions.yaml. | |
| #526 Destructive mode does not allow for building charms in parallel | charmcraft | closed | Parallel destructive mode builds failed due to shared apt lock paths. Resolved by integrating craft-parts 1.0.1 to namespace build directories by charm name. Fix released in Charmcraft 1.3.0. | |
| #1697 Charmcraft 3 breaks charms with multiple run-on architectures | charmcraft | closed | Closed as blocked by an upstream fix in craft-application. Charmcraft 3 incorrectly concatenated multiple run-on architectures into a single invalid string, causing build failures. Resolution awaits the referenced upstream issue. |