Debugging Builds#
This guide covers how to debug conda package builds with rattler-build when things go wrong. It's designed for both humans and AI agents working with recipes.
Debugging Workflow#
Suppose you have a recipe that fails to build:
Running rattler-build build will fail. When a build
fails, the build directory is automatically preserved so you can investigate.
There are multiple things you can do to investigate
Enter the Debug Shell#
Jump straight into the failed build environment:
This opens an interactive shell in the work directory with the build environment
loaded. All environment variables ($PREFIX, $BUILD_PREFIX, etc.) are set up
exactly as they were during the build.
Now you can modify files and run individual commands to isolate the issue:
Re-run the Build Script#
Use debug run to re-execute the build script with the full environment already
loaded:
# Re-run the build script
rattler-build debug run
# Re-run with shell tracing (bash -x) for verbose output
rattler-build debug run --trace
You can find the working directory by running the following:
Modify files inside that directory and run rattler-build debug run to check whether that fixed the problem.
Modify Dependencies#
If you need additional packages in the host or build environment, you can add them without re-running the full setup:
# Add packages to the host environment
rattler-build debug host-add libfoo libbar
# Add build tools
rattler-build debug build-add gdb valgrind
Remember to add them to your recipe.yaml once you found the right set of dependencies.
Create a Patch for Fixes#
After fixing issues in the source code:
# Create a patch from your changes
rattler-build debug create-patch \
--directory . \
--name my-fix \
--exclude "*.o,*.so,*.pyc"
# Preview what would be included
rattler-build debug create-patch \
--directory . \
--name my-fix \
--dry-run
To include new files:
In the end, you will have a patch file that you can include in your recipe
Update Recipe and Rebuild#
Add the patch to your recipe:
source:
- url: https://example.com/source.tar.gz
sha256: ...
patches:
# this needs to be manually added
- my-fix.patch
Then rebuild:
Debugging a Successful Build#
If your recipe builds successfully but you still want to inspect the
environment, use --keep-build to prevent cleanup:
Setting Up a Debug Environment Without Building#
If you want to prepare a debug environment without running the build script at
all, use debug setup. This resolves dependencies, downloads sources, and
creates the build script — but doesn't execute it:
This is useful when you want to inspect or modify sources before running the build for the first time.
Inspecting and Extracting Packages#
The rattler-build package subcommand provides utilities for inspecting and extracting built packages, which is useful for debugging package contents.
Inspecting Packages#
Use package inspect to view package metadata without extracting:
# Basic package information
rattler-build package inspect mypackage-1.0-h12345.conda
# Show all information including file listing
rattler-build package inspect mypackage-1.0-h12345.conda --all
# Show specific sections
rattler-build package inspect mypackage-1.0-h12345.conda --paths # File listing with hashes
rattler-build package inspect mypackage-1.0-h12345.conda --about # Extended about info
rattler-build package inspect mypackage-1.0-h12345.conda --run-exports # Run exports
# Output as JSON for scripting
rattler-build package inspect mypackage-1.0-h12345.conda --json
Extracting Packages#
Use package extract to extract a package to a directory for inspection:
# Extract to a directory named after the package
rattler-build package extract mypackage-1.0-h12345.conda
# Extract to a custom destination
rattler-build package extract mypackage-1.0-h12345.conda -d my-extracted
# Extract directly from a URL (supports authenticated channels)
rattler-build package extract https://conda.anaconda.org/conda-forge/linux-64/python-3.11.0-h12345.conda
After extraction, the command reports the SHA256/MD5 checksums and file size, which is useful for verifying package integrity.
Both .conda and .tar.bz2 package formats are supported.
Build Directory Structure#
When rattler-build builds a package, it creates:
output/
└─ rattler-build-log.txt # Append-only log of build directories (latest at bottom)
└─ bld/ # Build directories
│ └─ rattler-build_<name>_<timestamp>/
│ └─ work/ # Source code and working directory
│ │ └─ .source_info.json # Source information (extracted folders, etc.)
│ │ └─ build_env.sh # Environment setup script
│ │ └─ conda_build.sh # The actual build script (sources `build_env.sh`)
│ │ └─ conda_build.log # Complete build output
│ └─ host_env_placehold_.../ # Host environment (runtime dependencies)
│ └─ build_env/ # Build environment (build-time dependencies)
└─ src_cache/ # Downloaded and extracted sources
└─ build_cache/ # Staging cache (experimental)
│ └─ staging_<sha256>/ # Per-staging-output cache
│ └─ metadata.json # Cache metadata (deps, sources, variant)
│ └─ prefix/ # Cached prefix files from staging build
│ └─ work_dir/ # Cached work directory from staging build
└─ <platform>/ # Built packages
Environment Variables Available in the Debug Shell#
Inside the debug shell, you have access to:
| Variable | Description |
|---|---|
$PREFIX |
Host prefix (where packages get installed) |
$BUILD_PREFIX |
Build prefix (tools for building) |
$SRC_DIR |
Source directory (same as work directory) |
$RATTLER_BUILD_DIRECTORIES |
Full JSON with all directory info |
$RATTLER_BUILD_RECIPE_PATH |
Path to the recipe file |
$RATTLER_BUILD_RECIPE_DIR |
Directory containing the recipe |
$RATTLER_BUILD_BUILD_DIR |
The build directory root |
$RATTLER_BUILD_HOST_PREFIX |
Path to the host prefix |
$RATTLER_BUILD_BUILD_PREFIX |
Path to the build prefix |
Common Debugging Scenarios#
Compilation Failures#
# Re-run the build script with tracing to see where it fails
rattler-build debug run --trace
# Or enter the shell and run specific build commands
rattler-build debug shell
make VERBOSE=1
cmake --build . --verbose
Missing Files or Dependencies#
# Check source information
cat .source_info.json | jq .
# List what's in the work directory
find . -type f | head -30
# Check what's in the environments
ls $PREFIX/lib/
ls $BUILD_PREFIX/bin/
# Add a missing dependency on the fly
rattler-build debug host-add libmissing
Library Not Found Errors#
# Check if the library exists in PREFIX
find $PREFIX -name "lib*.so*" -o -name "lib*.dylib*"
# Check pkg-config paths
echo $PKG_CONFIG_PATH
pkg-config --libs --cflags libfoo
Build Log Analysis#
All build output is saved to conda_build.log:
# View the full log
less conda_build.log
# Search for errors
grep -i error conda_build.log
grep -i "undefined reference" conda_build.log
Debugging with AI Agents#
The debug subcommands are designed to work well with AI coding agents (Claude
Code, Codex, etc.) that cannot use interactive shells. The key principle is:
set up once, then iterate fast by re-running the build script.
Agent Workflow#
# 1. Set up the debug environment (slow, only once)
rattler-build debug setup --recipe recipe.yaml
# 2. Get the work directory
rattler-build debug workdir
# 3. Edit source files in work directory to fix the issue
# (agent edits files directly)
# 4. Re-run the build script (fast — no dependency resolution)
rattler-build debug run
# 5. If the build fails, go back to step 3
# 6. Once it works, create a patch
rattler-build debug create-patch --name my-fix
Key Points for Agents#
debug setupis non-interactive — it sets up everything and exits. Use this instead ofdebug shellwhich opens an interactive shell.debug workdirprints the work directory path to stdout — nojqor log parsing needed.debug runre-runs the build script with the environment already set up. Use--tracefor verbosebash -xoutput. This is the fast inner loop — it takes seconds, not minutes, because dependencies are already installed.debug host-add/debug build-addlet agents add missing dependencies without re-running the full setup.debug create-patchgenerates a unified diff from changes in the work directory. The agent can then add the patch to the recipe.
Parsing the Build Log#
The last line of output/rattler-build-log.txt is JSON:
{
"work_dir": "/path/to/output/bld/rattler-build_pkg_1234/work",
"build_dir": "/path/to/output/bld/rattler-build_pkg_1234",
"host_prefix": "/path/to/output/bld/rattler-build_pkg_1234/host_env_placehold_...",
"build_prefix": "/path/to/output/bld/rattler-build_pkg_1234/build_env",
"recipe_dir": "/path/to/recipe/dir",
"recipe_path": "/path/to/recipe.yaml",
"output_dir": "/path/to/output"
}
Understanding Relocatability#
rattler-build makes packages relocatable through:
-
RPATH patching - Changes
.dyliband.sofiles to use relative paths ($ORIGIN,@loader_path) usingpatchelforinstall_name_tool -
Placeholder replacement - At install time, replaces placeholder strings in binaries and text files with the actual prefix
Important: The placeholder is a long string (placehold_placehol_...). If your code has small buffer optimization or assumes static string lengths for file paths, you may need to adjust it. The $PREFIX length will differ at installation time. The placeholder replacement in binary files will overwrite the placeholder string, move the remainder until \0 is found in the original string, and pad with \0 bytes.
Useful Commands Reference#
# Build commands
rattler-build build --recipe recipe.yaml --keep-build
rattler-build build --recipe recipe.yaml --channel conda-forge --no-test
# Debug commands
rattler-build debug setup --recipe recipe.yaml # Set up environment
rattler-build debug shell # Open shell in last build
rattler-build debug shell --work-dir /path/to/work # Open shell in specific build
rattler-build debug workdir # Print work directory path
rattler-build debug run # Re-run build script
rattler-build debug run --trace # Re-run with bash -x tracing
rattler-build debug host-add python numpy # Add packages to host env
rattler-build debug build-add cmake # Add packages to build env
rattler-build debug create-patch --name fix # Create patch from changes
rattler-build debug create-patch --name fix --dry-run # Preview patch
# Test commands
rattler-build test --package-file output/linux-64/mypackage-1.0.tar.bz2