Most Python-based snaps can't build on core26
Metadata
Current evaluation
Resolved in PR #6089 and released in snapcraft 8.14.3. The python plugin now correctly handles core26 builds without assuming a system interpreter. Uv and poetry plugins remain unaddressed and will be fixed in future updates.
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
When building a snap with a Python-based plugin on core26, the following error is raised:
```
Don't know which interpreter to use for base core26.
Recommended resolution: Please contact the Snapcraft team.
```
This appears to be due to this function:
https://github.com/canonical/snapcraft/blob/8bd9cc5222a10e07b11727313b2e1080770ed854/snapcraft/parts/plugins/python_common.py#L42
An assumption is made that all cores will contain a usable Python interpreter, and furthermore, the snap _must_ use this provided Python interpreter even if they prefer to stage their own. This behavior can't work on core26, as there isn't a Python interpreter to use.
### Steps to reproduce
Attempt to build the attached project file.
### Environment
Snapcraft 8.14
### snapcraft.yaml
<details>
<summary>snapcraft.yaml</summary>
```yaml
name: microceph
base: core26
build-base: devel
adopt-info: ceph
grade: devel
source-code: https://github.com/canonical/microceph.git
license: AGPL-3.0
summary: Simple clustered Ceph deployment
description: |-
MicroCeph is snap-deployed Ceph with built-in clustering.
confinement: strict
package-repositories:
- type: apt
ppa: lmlogiudice/ceph-tentacle-resolute
plugs:
load-rbd:
interface: kernel-module-load
modules:
- name: rbd
load: on-boot
slots:
ceph-logs:
interface: content
content: logs
source:
read:
- "$SNAP_COMMON/logs"
ceph-conf:
interface: content
content: ceph-conf
source:
read:
- "$SNAP_DATA/conf"
environment:
LD_LIBRARY_PATH: $SNAP/lib:$SNAP/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$SNAP/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/ceph:$SNAP/lib:$SNAP/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$SNAP/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/ceph:$SNAP/lib/ganesha:$SNAP/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/ceph/compressor:$SNAP/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/ceph/crypto:$SNAP/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/ceph/erasure-code
PYTHONPATH: $SNAP/lib/python3/dist-packages:$SNAP/lib/python3.13/site-packages
layout:
/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/ceph:
symlink: $SNAP/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/ceph
/usr/lib/ganesha:
symlink: $SNAP/lib/ganesha
/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/rados-classes:
symlink: $SNAP/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/rados-classes
/etc/ceph:
bind: $SNAP_DATA/conf
/etc/ganesha:
bind: $SNAP_DATA/conf/ganesha
/usr/share/ceph:
bind: $SNAP/share/ceph
/var/lib/ceph:
bind: $SNAP_COMMON/data
/var/log/ceph:
bind: $SNAP_COMMON/logs
/var/log/ganesha:
bind: $SNAP_COMMON/logs/ganesha
apps:
# Service
daemon:
command: commands/daemon.start
daemon: simple
plugs:
- block-devices
- dm-crypt
- hardware-observe
- mount-observe
- network
- network-bind
- microceph-support
slots:
- microceph
mds:
command: commands/mds.start
daemon: simple
install-mode: disable
after:
- daemon
plugs:
- network
- network-bind
- process-control
mon:
command: commands/mon.start
daemon: simple
install-mode: disable
after:
- daemon
plugs:
- hardware-observe
- network
- network-bind
- process-control
mgr:
command: commands/mgr.start
daemon: simple
install-mode: disable
after:
- daemon
plugs:
- network
- network-bind
- process-control
nfs:
command: commands/nfs-ganesha.start
daemon: simple
install-mode: disable
after:
- daemon
plugs:
- network
- network-bind
- process-control
osd:
command: commands/osd.start
reload-command: commands/osd.reload
daemon: simple
install-mode: disable
stop-mode: sigterm-all
stop-timeout: 5m
after:
- daemon
plugs:
- block-devices
- dm-crypt
- hardware-observe
- network
- network-bind
- microceph-support
- process-control
rgw:
command: commands/rgw.start
daemon: simple
install-mode: disable
after:
- daemon
plugs:
- hardware-observe
- network
- network-bind
- process-control
"rbd-mirror":
command: commands/rbd-mirror.start
daemon: simple
install-mode: disable
after:
- daemon
plugs:
- network
- network-bind
- process-control
"cephfs-mirror":
command: commands/cephfs-mirror.start
daemon: simple
install-mode: disable
after:
- daemon
plugs:
- network
- network-bind
- process-control
# Commands
ceph:
command: commands/ceph
plugs:
- network
- home
"radosgw-admin":
command: commands/radosgw-admin
plugs:
- network
microceph:
command: commands/microceph
plugs:
- mount-observe
- network
- block-devices
- dm-crypt
- home
rbd:
command: commands/rbd
plugs:
- network
- network-bind
- microceph-support
- dm-crypt
rados:
command: commands/rados
plugs:
- network
ceph-bluestore-tool:
command: commands/ceph-bluestore-tool
plugs:
- mount-observe
- block-devices
- hardware-observe
ceph-authtool:
command: commands/ceph-authtool
plugs:
- home
parts:
microceph-orch:
plugin: python
# build-snaps:
# - astral-uv
source: ./microceph-orch
after:
- microceph
- ceph
override-prime: |
set -eux
a=$(pwd)
craftctl default
mkdir -p share/ceph/mgr/microceph
# Force copy to overwrite.
cp -rf lib/python3.14/site-packages/microceph share/ceph/mgr/
ceph:
plugin: nil
source: patches/
override-prime: |
craftctl default
pkg_version=$(
dpkg-deb -f \
$CRAFT_PART_SRC/../stage_packages/ceph-common*.deb Version)
git_version=$(
git -C $CRAFT_PROJECT_DIR describe \
--always \
--dirty \
--abbrev=10 | sed -s 's/^v//')
printf "ceph-version: ${pkg_version}\nmicroceph-git: ${git_version}\n" > share/metadata.yaml
override-stage: |
set -eux
craftctl default
pkg_version=$(
dpkg-deb -f \
$CRAFT_PART_SRC/../stage_packages/ceph-common*.deb \
Version | sed -rne 's/([0-9.]+)[-+].*$$/\1/p' | cut -c1-10)
git_version=$(
git -C $CRAFT_PROJECT_DIR describe \
--always \
--dirty \
--abbrev=10)
# changed as the original string was longer than 32chars.
craftctl set version=${pkg_version}+snap${git_version}
# Apply patches to the staging environment to ensure
# the microceph orchestrator is enabled.
pushd $CRAFT_STAGE
ls -l $CRAFT_PART_SRC/*.patch
for quirk in `ls -1 $CRAFT_PART_SRC/*.patch`
do
echo "Applying patch $quirk from directory $(pwd)"
patch -p1 < $quirk
echo "Done applying patch $quirk"
done
popd
stage-packages:
- ceph-common
- ceph-mds
- ceph-mgr
- ceph-mgr-dashboard
- ceph-mon
- ceph-osd
- radosgw
- rbd-mirror
- cephfs-mirror
# Utilities
- coreutils
- util-linux
- uuid-runtime
- python3-setuptools
- python3-packaging
- libatomic1
- python3-ceph-common # used by microceph-orch
organize:
usr/bin/: bin/
usr/sbin/: bin/
usr/lib/: lib/
usr/share/: share/
prime:
- bin/ceph
- bin/ceph-authtool
- bin/ceph-bluestore-tool
- bin/ceph-mds
- bin/ceph-mgr
- bin/ceph-mon
- bin/ceph-osd
- bin/ceph-conf
- bin/monmaptool
- bin/rbd
- bin/rados
- bin/radosgw
- bin/radosgw-admin
- bin/rbd-mirror
- bin/cephfs-mirror
- bin/truncate
- bin/uuidgen
- bin/findmnt
- lib/*/ceph
- lib/*/libaio.so*
- lib/*/libasn1.so*
- lib/*/libatomic.so*
- lib/*/libboost_context.so*
- lib/*/libboost_filesystem.so*
- lib/*/libboost_iostreams.so*
- lib/*/libboost_locale.so*
- lib/*/libboost_program_options.so*
- lib/*/libboost_python313.so*
- lib/*/libboost_thread.so*
- lib/*/libboost_url.so*
- lib/*/libcephfs.so*
- lib/*/libcephsqlite.so*
- lib/*/libcurl-gnutls.so*
- lib/*/libdaxctl.so*
- lib/*/libfuse3.so*
- lib/*/libibverbs.so*
- lib/*/libicudata.so*
- lib/*/libicui18n.so*
- lib/*/libicuuc.so*
- lib/*/liblber.so*
- lib/*/libldap.so*
- lib/*/liblua5.4.so*
- lib/*/libnbd.so*
- lib/*/libncurses.so*
- lib/*/libndctl.so*
- lib/*/libnghttp2.so*
- lib/*/libnuma.so*
- lib/*/liboath.so*
- lib/*/libpmem.so*
- lib/*/libpmemobj.so*
- lib/*/libpsl.so*
- lib/*/libpython3.13.so*
- lib/*/librabbitmq.so*
- lib/*/librados.so*
- lib/*/libradosgw.so*
- lib/*/libradosstriper.so.*
- lib/*/librbd.so*
- lib/*/librdmacm.so*
- lib/*/libroken.so*
- lib/*/librtmp.so*
- lib/*/libsasl2.so*
- lib/*/libsnappy.so*
- lib/*/libssh.so*
- lib/*/libwind.so*
- lib/*/libxml2.so*
- lib/python3
- lib/*/rados-classes
- lib/*/libtcmalloc.so*
- lib/*/libunwind.so*
- lib/*/liblmdb.so*
- share/ceph
dqlite:
source: https://github.com/canonical/dqlite
source-type: git
source-depth: 1
source-tag: v1.18.5
plugin: autotools
autotools-configure-parameters:
- --prefix=
- --enable-build-raft
stage-packages:
- libuv1
- libsqlite3-0
- liblz4-1
build-packages:
- make
- libuv1-dev
- liblz4-dev
- libsqlite3-dev
- pkg-config
organize:
usr/lib/: lib/
prime:
- lib/libdqlite*so*
- lib/libraft*so*
- lib/*/libuv*so*
microceph:
source: microceph/
after:
- dqlite
build-snaps:
- go
plugin: nil
override-pull: |
craftctl default
set -ex
# Download the dependencies
go get -d -v ./...
override-build: |
set -ex
git_diff="$( git -C $CRAFT_PROJECT_DIR status -uno --porcelain )"
if [ -n "$git_diff" ]; then
echo "=================================================="
echo "STOP the build: dirty worktree detected"
echo "$git_diff"
echo "=================================================="
exit 1
fi
# Setup build environment
export CGO_CFLAGS="-I${CRAFT_STAGE}/include/ -I${CRAFT_STAGE}/usr/local/include/"
export CGO_LDFLAGS="-L${CRAFT_STAGE}/lib/ -L${CRAFT_STAGE}/usr/local/lib/"
export CGO_LDFLAGS_ALLOW="(-Wl,-wrap,pthread_create)|(-Wl,-z,now)"
pkg_version=$( apt-cache policy ceph-common | awk '/Candidate:/{ print $2 }' )
git_version=$(
git -C $CRAFT_PROJECT_DIR describe \
--always \
--dirty \
--abbrev=10)
export MC_VERSION="ceph-version: $pkg_version; microceph-git: $git_version"
# Build the binaries
go build -trimpath -o "${CRAFT_PART_INSTALL}/bin/microceph" -ldflags "-X 'github.com/canonical/microceph/microceph/version.version=${MC_VERSION}'" ./cmd/microceph
go build -trimpath -o "${CRAFT_PART_INSTALL}/bin/microcephd" -tags=libsqlite3 -ldflags "-X 'github.com/canonical/microceph/microceph/version.version=${MC_VERSION}'" ./cmd/microcephd
# Strip binaries
strip -s "${CRAFT_PART_INSTALL}/bin/microceph"
strip -s "${CRAFT_PART_INSTALL}/bin/microcephd"
prime:
- bin/microceph
- bin/microcephd
nfs-ganesha:
plugin: nil
stage-packages:
- nfs-ganesha
- nfs-ganesha-ceph
- nfs-ganesha-rados-grace
organize:
sbin/: bin/
usr/bin/: bin/
usr/sbin/: bin/
usr/lib/: lib/
prime:
- bin/*
- lib/*/ganesha
- lib/*/libevent_core-*.so*
- lib/*/libganesha_*.so*
- lib/*/libnfsidmap.so*
- lib/*/libntirpc.so*
- lib/*/liburcu-bp.so*
- lib/*/libwbclient.so*
strip:
after:
- ceph
- dqlite
- microceph
plugin: nil
override-prime: |
set -x
# Strip libraries (excluding python3 scripts)
find "${CRAFT_PRIME}"/lib -type f \
-not -path "${CRAFT_PRIME}/lib/python3*/*" \
-exec strip -s {} +
wrappers:
plugin: dump
source: snapcraft/
```
</details>
### Log output
```shell
Don't know which interpreter to use for base core26.
Recommended resolution: Please contact the Snapcraft team.
```
Evaluation history
| Date | Model | Scores | Action | Summary |
|---|---|---|---|---|
| qwen/qwen3.6-35b-a3b | — | — | Resolved in PR #6089 and released in snapcraft 8.14.3. The python plugin now correctly handles core26 builds without assuming a system interpreter. Uv and poetry plugins remain unaddressed and will be fixed in future updates. | |
| qwen/qwen3.6-35b-a3b | — | — | Fixed in PR #6089 and released in snapcraft 8.14.3. The python plugin now correctly handles core26 by removing the hardcoded system interpreter assumption. Uv and poetry plugins require separate updates. | |
| qwen/qwen3.6-35b-a3b | — | — | Fixed in PR #6089 and released in snapcraft 8.14.3. The get_system_interpreter logic was updated to resolve the core26 Python plugin build failure. The uv and poetry plugins remain unfixed for subsequent updates. | |
| qwen/qwen3.6-35b-a3b | — | — | Fixed in snapcraft 8.14.3 via PR #6089. The python plugin now correctly handles core26 builds by updating interpreter detection logic. The uv and poetry plugins remain unfixed for future updates. | |
| qwen3.6-35b-a3b-mtp-q6 | — | — | Fixed in snapcraft 8.14.3 via PR #6089. The python plugin now correctly handles core26 builds without requiring a system interpreter. Uv and poetry plugins will be addressed separately. | |
| qwen3.6-35b-a3b-mtp-q6 | — | — | Resolved in PR #6089 and released in snapcraft 8.14.3. The python plugin now correctly handles core26 by deferring interpreter detection. The uv and poetry plugins remain unaddressed and will be fixed in subsequent updates. |
Update history
No update history recorded yet.
Related issues
| Issue | Project | State | Summary | Similarity |
|---|---|---|---|---|
| #6089 fix(plugins/python): fix core26 builds | snapcraft | merged | Merged to enable the Python plugin for strictly confined core26 snaps and add core26 spread tests. Approved by three reviewers, passed CI, and resolves #6020. | |
| #1660 Python plugin fails on core26: base snap does not include Python interpreter | craft-parts | open | Python plugin fails on core26 base due to missing Python interpreter; maintainers suggest implementing clearer error guidance | |
| #5407 Unable to build Python snaps using classic confinement with core24 using snapcraft 8.8.0 (8.x/stable) | snapcraft | closed | Resolved as a configuration issue. Classic Python snaps on core24 require explicitly adding python3.12-minimal to stage-packages and adjusting the app command. The developer acknowledged documentation gaps and announced upcoming Python plugin improvements. | |
| #786 Python plugin. Python is broken in core24 classic snaps if snap is used on an older Ubuntu LTS version | craft-parts | open | Python plugin bug: core24 classic snaps fail on older Ubuntu LTS (20.04/22.04) with 'No module named encodings'. Original problem fixed in Snapcraft 8.3.2 via PR #4946; residual follow-up tracked in snapcraft#5144. Inactive since Sept 2024. | |
| #5090 feat: add Snapcraft-specific Poetry plugin | snapcraft | merged | Merged a Snapcraft-specific Poetry plugin that extracts shared Python logic into a python_common module. Enabled for core22 and core24, resolves #5025, approved by two reviewers, and passed CI checks. | |
| #5408 Unable to build usable Python snaps which use Ubuntu-provided python3-* dependencies using strict confinement with core24 using snapcraft 8.8.0 (8.x/stable) | snapcraft | closed | Closed as completed. The author applied a PYTHONPATH workaround in snapcraft.yaml to access staged packages. Maintainers declined a code fix, marking the issue as a reference for a future Python plugin rewrite. |