Troubleshooting
Every message src2deb prints is prefixed src2deb:. This chapter is ordered by
when a message appears in a run — before it starts, while sources resolve, while
the order is computed, while a build root is provisioned, and while a component
builds.
A run that reaches the build phase ends with a summary and exits non-zero if any component failed. A run stopped before that point prints the error alone, writes no manifest, and has nothing to summarize.
Before the run starts
unrecognized option --x
src2deb: unrecognized option --nope
Try 'src2deb --help' for usage.
Exit status 2. Each subcommand accepts its own options: --build-deps belongs
to plan, and --keep-going, --jobs, --only, --from, and
--skip-published to build. See Command line.
the work directory is locked
src2deb: the work directory is locked by process 4127 (work/.lock); remove that
file if that process is gone
A run holds an exclusive lock on its work directory for its whole duration, so a
second run against the same --work is rejected rather than corrupting the
shared pool and output. plan takes the same lock, because it writes to
<work>/sources/.
Give the second run a --work directory of its own, or wait for the first. When
the named process is gone — a run killed outright, or ended by a second Ctrl-C,
leaves the lockfile behind — remove the file the message names. A lockfile
holding nothing readable as a process id reports the second form, “locked by
another run”.
suite "x" is not a numbered Debian release
src2deb: suite "sid" is not a numbered Debian release, so it has no known version
tag; pass --version-tag to name the tag builds for it should carry (for example
"debsid")
src2deb derives a version tag from the suite for each numbered Debian release, and refuses a suite it has no tag for rather than guessing one. Name the tag:
src2deb build recipes/cosmic-epoch --suite sid --version-tag debsid
A recipe written for such a suite may declare version-tag instead, which
applies to that recipe’s own suite. See
Package versions.
invalid selection
Two forms, both settled before a single source is cloned or a root provisioned.
A selection naming a component the recipe does not have:
src2deb: invalid selection: --only names unknown component "cosmic-osdd"
Check the name against recipe.toml, where component names are free-form.
And a --from whose own source failed:
src2deb: invalid selection: --from names component "cosmic-osd", whose source did
not resolve, so the components after it in the build order cannot be identified
--from names a position in the build order, and a component with no resolved
source has none. Fix the source, or name a different starting component.
unsatisfiable build-dependency
A component this run builds needs a package that another component of the recipe produces, and the run neither builds that component nor finds its package in the pool. Refused before anything is provisioned, where it would otherwise surface as a resolver failure deep inside the consumer’s build root.
The message names why the producer is absent, because that decides the fix. The selection left it out:
src2deb: unsatisfiable build-dependency: this run builds "cosmic-osd", which
build-depends on "libcosmic-randr-dev"; that package is produced by component
"cosmic-randr", which --only leaves out, and the pool does not hold it. Select
"cosmic-randr" as well, or build it first
Add the named component to the selection, or build it into the pool first — a pool that already holds the package satisfies the build-dependency, which is why this is refused only when the pool cannot cover it.
Or the producer’s every binary package is Architecture: all, and the recipe
leaves those to another architecture:
src2deb: unsatisfiable build-dependency: this run builds "cosmic-osd", which
build-depends on "cosmic-icons"; that package is produced by component
"cosmic-icons", which produces only Architecture: all packages, left to
"amd64" by this recipe, and the pool does not hold it. Stop naming an
arch-indep owner, so this architecture builds "cosmic-icons" itself; the
owner's copy is published to the owner's pool, which this build does not
resolve against
Drop arch-indep-owner so every architecture produces its own. Building for the
owner first does not settle this: a pool belongs to one architecture, so the
owner’s copy lands in the owner’s pool and this build never resolves against it.
See Who builds the Architecture: all
packages.
While sources resolve
resolving source for X
src2deb: FAILED cosmic-comp: resolving source for cosmic-comp: <reason>
A clone, fetch, checkout, or submodule update failed. Common causes are an
unreachable repository, a git-ref naming a branch or tag that does not exist,
and credentials for a private repository.
A resolve failure is a failure of that component rather than of the run, on the
same terms as a failed build: --keep-going carries the run past it, records the
component as failed with no source recorded, and folds it into the summary and
the manifest.
source.git names X, but the checkout at Y was cloned from Z
src2deb: FAILED cosmic-comp: resolving source for cosmic-comp: source.git names
"https://github.com/example/cosmic-comp", but the checkout at
/work/sources/cosmic-comp was cloned from
"https://github.com/pop-os/cosmic-comp"; delete that directory to build from the
repository the recipe names
The recipe was repointed at another repository — a fork, a mirror, a renamed upstream, or the same repository over another protocol — and the work directory still holds a checkout of the old one. Delete the checkout and build again:
rm -rf work/sources/cosmic-comp
A fetch takes its remote from the checkout rather than from the recipe, so the
alternative would be to build the old repository and record its commit as though
the recipe had asked for it. Repointing the checkout in place is not enough
either: the objects, tags, and default branch of the repository it was cloned
from survive a git remote set-url, so a ref that resolves only in the old
repository would still resolve. A packaging.git overlay is refused the same way,
and its checkout is under work/packaging/ instead.
The comparison is exact, so two spellings of one repository — a trailing /, a
.git suffix — are refused as well. The remedy is the same, and it costs one
re-clone.
A git insteadOf rewrite is not a repoint and does not trigger this. The URL
compared is the one the checkout was cloned from, not the one the rewrite sends
the fetch to, so a host that redirects github.com at an internal mirror builds
as it always did.
is stored with Git LFS, but git lfs is not available
src2deb: FAILED pop-icon-theme: resolving source for pop-icon-theme:
src/assets/wallpaper.png is stored with Git LFS, but `git lfs` is not available;
install git-lfs so the real content is fetched instead of the pointer stubs
standing in for it. Building against a pointer produces a package that installs
cleanly and fails at runtime, so the build stops here
Install git-lfs on the host:
sudo apt install git-lfs
A checkout made without LFS support writes a short text pointer where each asset should be. Those pointers are ordinary valid files, so a build embeds or installs one and succeeds — the substitution surfaces only when the installed program reads the asset and finds a stub. src2deb therefore stops at resolve instead.
is still a Git LFS pointer after git lfs pull
src2deb: FAILED pop-icon-theme: resolving source for pop-icon-theme:
src/assets/wallpaper.png is still a Git LFS pointer after `git lfs pull`; the
content could not be fetched from the LFS server. Building against a pointer
produces a package that installs cleanly and fails at runtime, so the build stops
here
git-lfs is installed and ran, and the content is still missing. The LFS server
was unreachable, the objects it should hold are gone, or the repository needs
credentials for LFS that the clone did not have. Both messages list up to five
pointer paths, then a count of the rest.
is a Git LFS pointer; run git lfs pull in X
src2deb: FAILED pop-icon-theme: resolving source for pop-icon-theme:
src/assets/wallpaper.png is a Git LFS pointer; run `git lfs pull` in
/home/someone/pop-icon-theme so the build gets the real content instead of the
pointer stub standing in for it. Building against a pointer produces a package
that installs cleanly and fails at runtime, so the build stops here
The same substitution, found in a source.path tree. Run the command the message
names, in the directory it names, and build again:
git -C /home/someone/pop-icon-theme lfs pull
src2deb does not fetch on your behalf here, as it does for a checkout it made itself. The tree is yours, and a build is not the moment to change it.
source.path X cannot be read
src2deb: FAILED cosmic-comp: resolving source for cosmic-comp:
source.path ../../checkouts/cosmic-comp cannot be read: No such file or
directory (os error 2)
The path is wrong, or it is relative to somewhere other than you expected. A
relative source.path resolves against the recipe’s directory — the one
holding recipe.toml — not against the directory you ran src2deb from. The
message shows the joined path, so compare it with where the tree actually is.
source.path X would be copied into itself
src2deb: FAILED cosmic-comp: resolving source for cosmic-comp:
source.path /home/someone/build would be copied into itself
(/home/someone/build/work/sources/cosmic-comp); point it at a tree outside the
work directory
The tree a path source names contains the work directory, or lies inside it. The
copy would either walk into its own output or be deleted by the wipe that
precedes it, so the component is refused. Move --work outside the source tree,
or point the source somewhere else.
the packaging source at X has no debian directory
src2deb: FAILED foo: resolving source for foo: the packaging source at
/work/packaging/foo/debian has no debian directory; a packaging overlay supplies
one, and packaging.subdir names the directory holding it rather than the
directory itself
Almost always the setting pointing one level too deep. A packaging overlay names
the directory that holds debian/, so a repository whose root is the packaging
tree needs no packaging.subdir at all, and one that keeps its packaging under
debian-packaging/foo/debian/ sets packaging.subdir = "debian-packaging/foo".
The other cause is a repository that genuinely has no packaging in it — check the
branch. Packaging repositories often keep debian/ on a branch of its own, which
packaging.git-ref selects.
packaging.subdir X names Y, which the source does not hold
src2deb: FAILED foo: resolving source for foo: packaging.subdir debian/foo names
/work/packaging/foo/debian/foo, which the source does not hold
The subdirectory is not in the tree that was checked out. The same message
appears for source.subdir against a component’s own source. Compare the path in
the message with the tree under the work directory, and check
packaging.git-ref: a subdirectory that exists on one branch need not exist on
another.
the packaging source X and the component's source tree Y sit inside one another
src2deb: FAILED foo: resolving source for foo: the packaging source
/work/sources/foo and the component's source tree /work/sources/foo sit inside
one another, so the overlay would be copied onto itself; point packaging at a
tree outside the work directory
A packaging.path pointing into src2deb’s own work directory, usually at the
copy of the source it is meant to overlay. The overlay’s destination is removed
before the copy, so this would delete the tree it was about to read. Point
packaging.path at the packaging as you keep it — beside the recipe, or wherever
you edit it — rather than at anything under --work.
patch X does not apply
src2deb: FAILED cosmic-comp: resolving source for cosmic-comp: patch
recipes/cosmic-epoch/patches/cosmic-comp/0001-fix-build.patch does not apply to
/work/sources/cosmic-comp: error: patch failed: src/shell/mod.rs:412
error: src/shell/mod.rs: patch does not apply
The source moved out from under the patch, which is what happens when a component tracks a branch. src2deb does not fuzz a patch or fall back to a three-way merge, so a patch that no longer matches has to be brought up to date or dropped:
# See what the patch expects against what the source now holds.
cd work/sources/cosmic-comp
git apply --check -v ../../../recipes/cosmic-epoch/patches/cosmic-comp/0001-fix-build.patch
Rebase the patch against the current source and export it again with git format-patch, or pin source.git-ref to the commit the patch was written
against. See Patches.
patch X cannot be read
src2deb: FAILED cosmic-comp: resolving source for cosmic-comp: patch
recipes/cosmic-epoch/patches/fix.patch cannot be read: No such file or
directory (os error 2)
A patch path is relative to the recipe’s directory — the one holding
recipe.toml — not to the directory you ran src2deb from. The message shows the
joined path, so compare it with where the file actually is.
skipping X (not selected); its source did not resolve
src2deb: skipping cosmic-player (not selected); its source did not resolve: <reason>
Reported, then passed over, whatever --keep-going says. Every run resolves
every component’s source because the build order is read from all of them, so a
narrowed run still clones the whole recipe — but a component the run was never
going to build does not fail it. The recipe still has a problem the next full run
will hit.
While the order is computed
cannot order the build: a dependency cycle
src2deb: cannot order the build: a dependency cycle involves: cosmic-osd, cosmic-randr
Two or more components each build-depend on a package another produces, so no
order satisfies them all. This ends the run outright: there is nothing coherent
to build. Break the cycle in the components’ debian/control files.
reading debian/control for X
src2deb: FAILED cosmic-comp: reading debian/control for cosmic-comp: <reason>
The resolved tree has no debian/control, or it will not parse. Check the
component’s source.subdir — a component inside a superproject needs it to point
at the directory holding the debian/ tree. debian/changelog reports the same
way.
While a build root is provisioned
provisioning a build root
src2deb: FAILED cosmic-comp: provisioning a build root: <reason>
Most often a build-dependency the target suite’s archive cannot satisfy, which is
what an unsuitable --suite surfaces as: the flag retargets a recipe without
promising the recipe suits the target. Check that the component’s
Build-Depends exist in the suite you asked for, and add a [[repositories]]
entry for anything that lives elsewhere. See
Sources and the toolchain.
A foreign-architecture target with no qemu-user binfmt handler also fails here,
naming the missing handler. See Requirements.
installing the rustup X toolchain into a build root
src2deb: FAILED cosmic-comp: installing the rustup 1.95.0 toolchain into a build
root: <what the installer wrote>
The recipe pins a rustup toolchain and the install failed. The installer’s output
is captured rather than streamed, so the message carries it. Common causes are a
version rustup does not publish for the target architecture and a host that
cannot reach https://sh.rustup.rs.
While a component builds
vendoring X: debian/rules clean
src2deb: FAILED cosmic-comp: vendoring cosmic-comp: debian/rules clean exited with status 2
The vendor pass failed. It runs with the host’s network so the component can
fetch its crates, so this is usually a network problem or an upstream vendoring
step that needs a tool the recipe has yet to declare. extra-build-deps adds one:
extra-build-deps = ["just"]
Re-run with -v to see the pass announced, and read the in-cage output above the
failure for what the vendoring step itself reported.
building X: dpkg-buildpackage
src2deb: FAILED cosmic-comp: building cosmic-comp: dpkg-buildpackage exited with status 2
An ordinary build failure. The build’s own output is above the message, indented
by two spaces. The build pass runs offline from the vendor.tar the vendor pass
produced, so a build reporting a failed download means the vendoring step missed
something.
Both streams of the build render alike, because dpkg-buildpackage writes its
ordinary progress to standard error. A line’s stream says nothing about its
severity.
Notes that are not failures
A run reports these whatever it was asked to print, because each changes what
the run guarantees rather than what it is doing. The first two report at every
verbosity above -q; an unsatisfiable dependency reports even at -q, since it
is an answer rather than a narrative.
no unprivileged overlay
src2deb: note: no unprivileged overlay (<reason>); using full reprovisioning,
which reuses a root a build has written to
The host cannot establish an unprivileged overlay, so src2deb bakes a full root per component instead of layering each component’s build-dependencies over one shared base. Builds still work. They are slower, and a reused root carries the previous build’s writes, which is the weaker of the two isolation guarantees. See Build roots.
foreign-architecture build
src2deb: foreign-architecture build: target arm64, host amd64 (runs through
qemu-user; needs qemu-user-static and binfmt with the F flag)
Every compiler invocation runs under emulation, which costs roughly an order of
magnitude in compile time. Expected when you asked for a foreign target;
otherwise check --architecture and the recipe’s architectures field. See
Cross-architecture builds.
An unsatisfiable dependency after a successful build
src2deb: arm64: cosmic-initial-setup-casper: Depends: casper
src2deb: arm64: 67 package(s), 206 dependencies, 1 unsatisfiable
The named package built and published, and apt will refuse to install it: nothing in the suite, in the recipe’s repositories, or in the pool provides what it depends on. The build is not wrong — this is a property of the packaging and the suite, not of the run — so it reports rather than fails.
src2deb check asks the same question on its own and exits non-zero, which is
the form to put in front of a publish. See
Checking installability, which covers what to do about a
finding.
could not check whether the packages install
The run finished and its closing check could not reach the archive to ask. The
packages are built and published; only the question went unanswered. Run
src2deb check when the archive is reachable again.
Stopping and resuming
cancelled; stopping
Ctrl-C stops a run at the next point where stopping leaves a coherent state
behind, so it can take until the current package, increment, or configure step
finishes. The run exits 130. A second Ctrl-C exits immediately and leaves the
lockfile behind.
Components that finished stay built, published, and recorded. Re-run with
--skip-published to pick up where it stopped. See
What a cancelled run leaves behind.
A re-run rebuilds everything
--skip-published reads the manifest for the recipe, suite, and architecture the
run targets, and skips a component whose source resolves to what is recorded as
built. A run that rebuilds everything is reading a different manifest or a
different source: check that --work, --suite, and --architecture match the
earlier run, and that the component’s git-ref is a pinned commit rather than a
branch that has since moved.
A source.path component is rebuilt every run by design, whatever the manifest
records. A path says where a tree was read from and not what it held, so nothing
about it establishes that the source has not moved. See Resume
state.
A build root is rebuilt when nothing changed
A root is cached on the exact set of packages a bootstrap would install — each one’s name, version, and archive checksum — plus the recipe’s pinned toolchain version. Any of those moving in the archive rebuilds the root from clean, which is what keeps a bumped build-dependency from silently reusing a root provisioned for the old set. See The build-root cache.