← Back to issue list

Packing a charm sometimes fails with "Too many levels of symbolic links"

View original Github issue

Metadata

Project
charmcraft
Number
#2661
Type
issue
State
closed
Author
dwilding
Labels
Created
Updated
Closed

Current evaluation

Closed without a fix. Packing charms with .tox or .venv directories triggers a symlink error that persists in destructive mode. Users rely on manually removing these directories before packing as a workaround.

Suggested action:

No scores available.

Issue body

### Check existing issues - [x] I've verified that this bug isn't described by any existing issues. ### Bug description Packing a charm that has a `.tox` or a `.venv` directory can fail with a "Too many levels of symbolic links" error: ```text OSError: [Errno 40] Too many levels of symbolic links: '/root/project/.tox/lint/lib64' ``` and ```text OSError: [Errno 40] Too many levels of symbolic links: '/home/ubuntu/tinyproxy/.venv/bin/python3.12' ``` See the log output below for more context. I haven't been able to reproduce this myself, but @james-garner-canonical and I have observed other people running into the issue. The context is: - Working inside a Multipass VM on a Mac - Used tox to run a development command (so that `.tox` is created) or used uv to manage the charm's dependencies (so that `.venv` is created) - Then packed the charm, not using destructive mode If packing fails, deleting `.tox`/`.venv` before packing again seems to help. Using destructive mode seems to help. (I'm sorry these resolution steps aren't more precise.) ### Steps to reproduce See above ### Environment Multipass on a Mac. Not destructive mode. ### charmcraft.yaml ```yaml # This file configures Charmcraft. # See https://documentation.ubuntu.com/charmcraft/stable/reference/files/charmcraft-yaml-file/ type: charm name: tinyproxy title: Reverse Proxy Demo summary: A demo charm that configures tinyproxy as a reverse proxy. description: | This charm demonstrates how to write a machine charm with Ops. # Documentation: # https://documentation.ubuntu.com/charmcraft/stable/howto/build-guides/select-platforms/ base: ubuntu@24.04 platforms: amd64: arm64: assumes: - juju >= 3.6 parts: charm: plugin: uv source: . build-snaps: - astral-uv # (Optional) Configuration options for the charm # This config section defines charm config options, and populates the Configure # tab on Charmhub. # More information on this section at: # https://documentation.ubuntu.com/charmcraft/stable/reference/files/charmcraft-yaml-file/#config # General configuration documentation: # https://documentation.ubuntu.com/juju/3.6/reference/configuration/#application-configuration config: options: slug: description: "Configures the path of the reverse proxy. Must match the regex [a-z0-9-]+" default: example type: string ``` ### Log output ```shell :: ## User environment :: 2026-03-26 08:32:23.513 plugin validation command: 'uv --version' :: 2026-03-26 08:32:23.739 executed uv --version with output uv 0.11.1 (a6042f67f 2026-03-24 aarch64-unknown-linux-gnu) :: 2026-03-26 08:32:23.739 set repository attribute: attr=stage_packages_filters, value=None, repo:<class 'craft_parts.packages.deb.Ubuntu'> :: 2026-03-26 08:32:23.739 Pulling charm :: 2026-03-26 08:32:23.739 execute action charm:Action(part_name='charm', step=Step.PULL, action_type=ActionType.RUN, reason=None, project_vars=ProjectVarInfo(root={}), properties=ActionProperties(changed_files=None, changed_dirs=None)) :: 2026-03-26 08:32:23.921 /root/project/.tox/lint/lib64: Too many levels of symbolic links :: 2026-03-26 08:32:23.921 Detailed information: OSError: filename: '/root/project/.tox/lint/lib64' :: 2026-03-26 08:32:23.924 Traceback (most recent call last): :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_parts/utils/file_utils.py", line 96, in link_or_copy :: 2026-03-26 08:32:23.924 copy(source, destination) :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_parts/utils/file_utils.py", line 173, in copy :: 2026-03-26 08:32:23.924 shutil.copy2(source, destination, follow_symlinks=follow_symlinks) :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/current/usr/lib/python3.12/shutil.py", line 476, in copy2 :: 2026-03-26 08:32:23.924 copystat(src, dst, follow_symlinks=follow_symlinks) :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/current/usr/lib/python3.12/shutil.py", line 388, in copystat :: 2026-03-26 08:32:23.924 _copyxattr(src, dst, follow_symlinks=follow) :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/current/usr/lib/python3.12/shutil.py", line 330, in _copyxattr :: 2026-03-26 08:32:23.924 names = os.listxattr(src, follow_symlinks=follow_symlinks) :: 2026-03-26 08:32:23.924 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: 2026-03-26 08:32:23.924 OSError: [Errno 40] Too many levels of symbolic links: '/root/project/.tox/lint/lib64' :: 2026-03-26 08:32:23.924 :: 2026-03-26 08:32:23.924 During handling of the above exception, another exception occurred: :: 2026-03-26 08:32:23.924 Traceback (most recent call last): :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_application/services/lifecycle.py", line 318, in run :: 2026-03-26 08:32:23.924 self._exec(actions) :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_application/services/lifecycle.py", line 342, in _exec :: 2026-03-26 08:32:23.924 aex.execute(action, stdout=stream, stderr=stream) :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_parts/executor/executor.py", line 342, in execute :: 2026-03-26 08:32:23.924 self._executor.execute(actions, stdout=stdout, stderr=stderr) :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_parts/executor/executor.py", line 136, in execute :: 2026-03-26 08:32:23.924 self._run_action(act, stdout=stdout, stderr=stderr) :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_parts/executor/executor.py", line 229, in _run_action :: 2026-03-26 08:32:23.924 handler.run_action(action, stdout=stdout, stderr=stderr) :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_parts/executor/part_handler.py", line 309, in run_action :: 2026-03-26 08:32:23.924 state = handler(step_info, stdout=stdout, stderr=stderr) :: 2026-03-26 08:32:23.924 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_parts/executor/part_handler.py", line 335, in _run_pull :: 2026-03-26 08:32:23.924 self._run_step( :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_parts/executor/part_handler.py", line 674, in _run_step :: 2026-03-26 08:32:23.924 return step_handler.run_builtin() :: 2026-03-26 08:32:23.924 ^^^^^^^^^^^^^^^^^^^^^^^^^^ :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_parts/executor/step_handler.py", line 139, in run_builtin :: 2026-03-26 08:32:23.924 return handler() :: 2026-03-26 08:32:23.924 ^^^^^^^^^ :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_parts/executor/step_handler.py", line 143, in _builtin_pull :: 2026-03-26 08:32:23.924 self._source_handler.pull() :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_parts/sources/local_source.py", line 105, in pull :: 2026-03-26 08:32:23.924 file_utils.link_or_copy_tree( :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_parts/utils/file_utils.py", line 255, in link_or_copy_tree :: 2026-03-26 08:32:23.924 copy_function(source, destination) :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_parts/utils/file_utils.py", line 111, in link_or_copy :: 2026-03-26 08:32:23.924 copy(source, destination, follow_symlinks=follow_symlinks) :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_parts/utils/file_utils.py", line 173, in copy :: 2026-03-26 08:32:23.924 shutil.copy2(source, destination, follow_symlinks=follow_symlinks) :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/current/usr/lib/python3.12/shutil.py", line 476, in copy2 :: 2026-03-26 08:32:23.924 copystat(src, dst, follow_symlinks=follow_symlinks) :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/current/usr/lib/python3.12/shutil.py", line 388, in copystat :: 2026-03-26 08:32:23.924 _copyxattr(src, dst, follow_symlinks=follow) :: 2026-03-26 08:32:23.924 File "/snap/charmcraft/current/usr/lib/python3.12/shutil.py", line 330, in _copyxattr :: 2026-03-26 08:32:23.924 names = os.listxattr(src, follow_symlinks=follow_symlinks) :: 2026-03-26 08:32:23.924 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: 2026-03-26 08:32:23.924 OSError: [Errno 40] Too many levels of symbolic links: '/root/project/.tox/lint/lib64' 2026-03-26 08:32:24.278 Executing on host: lxc --project charmcraft config device show local:charmcraft-tinyproxy-arm64-975 2026-03-26 08:32:24.347 Executing on host: lxc --project charmcraft config device remove local:charmcraft-tinyproxy-arm64-975 disk-/root/.cache/pip 2026-03-26 08:32:24.433 Executing on host: lxc --project charmcraft config device remove local:charmcraft-tinyproxy-arm64-975 disk-/root/project 2026-03-26 08:32:24.513 Executing on host: lxc --project charmcraft config device remove local:charmcraft-tinyproxy-arm64-975 disk-/tmp/craft-state 2026-03-26 08:32:24.599 Executing on host: lxc --project charmcraft stop local:charmcraft-tinyproxy-arm64-975 2026-03-26 08:32:28.532 Executing on host: lxc --project charmcraft list local: --format=yaml 2026-03-26 08:32:28.613 Executing on host: lxc --project charmcraft list local: --format=yaml 2026-03-26 08:32:28.735 Executing on host: lxc --project charmcraft list local: --format=yaml 2026-03-26 08:32:28.880 Executing on host: lxc --project charmcraft config set local:charmcraft-tinyproxy-arm64-975 user.craft_providers.status FINISHED 2026-03-26 08:32:28.969 Failed to run charmcraft in instance 2026-03-26 08:32:28.980 Traceback (most recent call last): 2026-03-26 08:32:28.980 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_application/services/provider.py", line 471, in run_managed 2026-03-26 08:32:28.980 instance.execute_run( # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType] 2026-03-26 08:32:28.980 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_providers/lxd/lxd_instance.py", line 257, in execute_run 2026-03-26 08:32:28.980 return self.lxc.exec( 2026-03-26 08:32:28.980 ^^^^^^^^^^^^^^ 2026-03-26 08:32:28.980 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_providers/lxd/lxc.py", line 393, in exec 2026-03-26 08:32:28.980 return runner(final_cmd, timeout=timeout, check=check, **kwargs) 2026-03-26 08:32:28.980 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2026-03-26 08:32:28.980 File "/snap/charmcraft/current/usr/lib/python3.12/subprocess.py", line 571, in run 2026-03-26 08:32:28.980 raise CalledProcessError(retcode, process.args, 2026-03-26 08:32:28.980 subprocess.CalledProcessError: Command '['lxc', '--project', 'charmcraft', 'exec', 'local:charmcraft-tinyproxy-arm64-975', '--cwd', '/root/project', '--', 'env', 'CRAFT_MANAGED_MODE=1', 'CHARMCRAFT_DEBUG=False', 'CHARMCRAFT_LXD_REMOTE=local', 'CHARMCRAFT_LAUNCHPAD_INSTANCE=production', 'CHARMCRAFT_MANAGED_MODE=1', 'DEBIAN_FRONTEND=noninteractive', 'DEBCONF_NONINTERACTIVE_SEEN=true', 'DEBIAN_PRIORITY=critical', 'CRAFT_PLATFORM=arm64', 'CRAFT_VERBOSITY_LEVEL=BRIEF', 'charmcraft', 'pack']' returned non-zero exit status 1. 2026-03-26 08:32:28.980 2026-03-26 08:32:28.980 The above exception was the direct cause of the following exception: 2026-03-26 08:32:28.980 Traceback (most recent call last): 2026-03-26 08:32:28.980 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_application/application.py", line 663, in run 2026-03-26 08:32:28.980 return_code = self._run_inner() 2026-03-26 08:32:28.980 ^^^^^^^^^^^^^^^^^ 2026-03-26 08:32:28.980 File "/snap/charmcraft/7519/lib/python3.12/site-packages/charmcraft/application/main.py", line 143, in _run_inner 2026-03-26 08:32:28.980 return super()._run_inner() 2026-03-26 08:32:28.980 ^^^^^^^^^^^^^^^^^^^^ 2026-03-26 08:32:28.980 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_application/application.py", line 640, in _run_inner 2026-03-26 08:32:28.980 return_code = dispatcher.run() or os.EX_OK 2026-03-26 08:32:28.980 ^^^^^^^^^^^^^^^^ 2026-03-26 08:32:28.980 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_cli/dispatcher.py", line 564, in run 2026-03-26 08:32:28.980 return self._loaded_command.run(self._parsed_command_args) 2026-03-26 08:32:28.980 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2026-03-26 08:32:28.980 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_application/commands/base.py", line 200, in run 2026-03-26 08:32:28.980 result = self._run(parsed_args, **kwargs) or result 2026-03-26 08:32:28.980 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2026-03-26 08:32:28.980 File "/snap/charmcraft/7519/lib/python3.12/site-packages/charmcraft/application/commands/lifecycle.py", line 167, in _run 2026-03-26 08:32:28.980 result = super()._run(parsed_args, step_name, **kwargs) 2026-03-26 08:32:28.980 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2026-03-26 08:32:28.980 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_application/commands/lifecycle.py", line 619, in _run 2026-03-26 08:32:28.980 return super()._run(parsed_args=parsed_args, step_name=step_name) 2026-03-26 08:32:28.980 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2026-03-26 08:32:28.980 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_application/commands/lifecycle.py", line 232, in _run 2026-03-26 08:32:28.980 self._run_manager_for_build_plan(fetch_service_policy) 2026-03-26 08:32:28.980 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_application/commands/lifecycle.py", line 97, in _run_manager_for_build_plan 2026-03-26 08:32:28.980 provider.run_managed(build, bool(fetch_service_policy)) 2026-03-26 08:32:28.980 File "/snap/charmcraft/7519/lib/python3.12/site-packages/craft_application/services/provider.py", line 478, in run_managed 2026-03-26 08:32:28.980 raise craft_providers.ProviderError( 2026-03-26 08:32:28.980 craft_providers.errors.ProviderError: Failed to run charmcraft in instance 2026-03-26 08:32:28.980 Full execution log: '/home/ubuntu/.local/state/charmcraft/log/charmcraft-20260326-082831.211082.log' ```

Evaluation history

Date Model Scores Action Summary
qwen/qwen3.6-35b-a3b Closed without a fix. Packing charms with .tox or .venv directories triggers a symlink error that persists in destructive mode. Users rely on manually removing these directories before packing as a workaround.
qwen/qwen3.8-27b
Impact: 55
Quick Win: 22.0
Staleness: 45
Complexity: 60
Confidence: 70
Support Request: 5
keep open Charmcraft pack fails with 'Too many levels of symbolic links' when .tox/.venv dirs exist in source. Reproduced on M3 Mac by maintainer; no fix yet, workaround is deleting those dirs before packing.
qwen3.6-35b-a3b-mtp-q6
Staleness: 45
Complexity: 55
Confidence: 90
Support Request: 15
needs triage Charm packing fails with symlink errors when .tox or .venv directories exist. The issue includes detailed logs and reproduction steps but remains unlabelled and unacknowledged by maintainers after ~3 months.
qwen3.6-35b-a3b-mtp-q6
Staleness: 60
Complexity: 40
Confidence: 85
Support Request: 10
needs triage Charm packing fails with symlink errors when .tox or .venv directories are present. Issue is open, unlabelled, and awaiting maintainer triage despite recent contributor confirmation.
qwen3.6-35b-a3b-mtp-q6
Staleness: 60
Complexity: 45
Confidence: 85
Support Request: 10
needs triage Charm packing fails with symlink errors when .tox or .venv directories are present. Issue is open, unlabelled, and awaiting maintainer triage.
qwen3.6-35b-a3b-mtp-q6
Staleness: 40
Complexity: 35
Confidence: 90
Support Request: 5
needs triage Charm packing fails with a symbolic link error when .tox or .venv directories exist. Open and under discussion, with multiple Mac contributors reproducing it. Workarounds involve deleting these directories or using destructive mode, awaiting fix.

Update history

Date Change
closed

Related issues

No related issues found above the similarity threshold.