jdx/mise · error · eyre::Report
[dotfiles]."{}": source does not exist: {}
Error message
[dotfiles]."{}": source does not exist: {} What it means
When building an OCI image, `[oci.dotfiles]` entries with mode symlink, copy, or symlink-each copy content from a local source path into the image. Before collecting files, mise verifies that the source path exists; a missing path aborts the build, naming the entry's key and the offending path. Mode 'content' (inline text) is exempt because it has no source file.
Source
Thrown at src/oci/builder.rs:866
fn resolve_layer_owner(opts_owner: Option<LayerOwner>, oci: &OciConfig) -> LayerOwner {
opts_owner.unwrap_or_else(|| {
let uid = oci.user_id.unwrap_or(0);
let gid = oci.group_id.unwrap_or(uid);
LayerOwner::new(uid, gid)
})
}
fn build_dotfiles_layer(
cfg: &Config,
requests: &[FileRequest],
owner: LayerOwner,
) -> Result<LayerBlob> {
let mut entries = DotfilesLayerEntries::default();
for req in requests {
if req.mode != FileMode::Content && !req.source.exists() {
bail!(
"[dotfiles].\"{}\": source does not exist: {}",
req.target_raw,
req.source.display()
);
}
match req.mode {
FileMode::Symlink | FileMode::Copy => {
collect_source_as_files(&req.source, &oci_target_path(req)?, &mut entries)
.wrap_err_with(|| {
format!("adding [dotfiles].\"{}\" to OCI image", req.target_raw)
})?;
}
FileMode::SymlinkEach => {
if !req.source.is_dir() {
bail!(
"[dotfiles].\"{}\": mode symlink-each requires a directory source: {}",
req.target_raw,View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Create the source file, or point the entry at a path that exists on the build machine
- For machine-independent content, switch to `mode = "content"` with inline text instead of a source path
- Use absolute paths (and correct tilde handling) for dotfile sources in CI contexts
Example fix
# before (mise.toml)
[oci.dotfiles]
"~/.gitconfig" = { source = "./gitconfig", mode = "copy" }
# but ./gitconfig does not exist
# after (mise.toml)
[oci.dotfiles]
"/root/.gitconfig" = { mode = "content", content = "[user]\n\tname = CI\n" } Defensive patterns
Strategy: validation
Validate before calling
python3 - <<'EOF'
import tomllib, os, sys
cfg = tomllib.load(open('mise.toml', 'rb'))
for target, spec in (cfg.get('oci', {}).get('dotfiles', {}) or {}).items():
mode = spec.get('mode', 'symlink') if isinstance(spec, dict) else 'symlink'
src = spec.get('source') if isinstance(spec, dict) else None
if mode != 'content' and src and not os.path.exists(os.path.expanduser(src)):
sys.exit(f'dotfiles {target!r}: missing source {src}')
print('dotfile sources OK')
EOF Prevention
- Use absolute paths for dotfile sources in CI; don't assume the dev's home layout
- Prefer mode = "content" for small config files to remove filesystem dependencies
- Add a pre-build check that every non-content dotfile source exists
When it happens
Trigger: A mise.toml `[oci.dotfiles]` entry like `"~/.gitconfig" = { source = "~/.gitconfig", mode = "symlink" }` where the file does not exist on the build machine (tilde not expanded as expected, path typo, or file only present on another host).
Common situations: Building images on CI where the dotfile exists only on a developer laptop; typos in relative paths resolved against the project dir; the file genuinely not created yet.
Related errors
- [dotfiles]."{}": mode symlink-each requires a directory sour
- [dotfiles]: duplicate OCI path {path:?} as both file and dir
- oci mount_point must not be empty
- oci mount_point must be an absolute path (got {mount_point:?
- [dotfiles]: duplicate OCI file path {path:?}
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/5b93e9c0ea4a3866.
Report an issue: GitHub.