multica-ai/multica · error
chmod temp for %s: %w
Error message
chmod temp for %s: %w
What it means
writeFileAtomic could not Chmod the temp file to the requested mode (0600 for configs that may hold inline secrets). The data is already written; only tightening permissions failed. On some filesystems chmod is unsupported or partially emulated, and the helper refuses to publish a file with looser permissions than intended.
Source
Thrown at server/internal/daemon/execenv/hermes_home.go:927
// writeFileAtomic writes data to a temp file in the destination directory with
// the given perms, then renames it over dst — so readers never see a partial
// file and a prior file's looser permissions are replaced.
func writeFileAtomic(dst string, data []byte, perm os.FileMode) error {
dir := filepath.Dir(dst)
tmp, err := os.CreateTemp(dir, ".hermes-tmp-*")
if err != nil {
return fmt.Errorf("create temp for %s: %w", dst, err)
}
tmpName := tmp.Name()
defer os.Remove(tmpName) // no-op once renamed
if _, err := tmp.Write(data); err != nil {
tmp.Close()
return fmt.Errorf("write temp for %s: %w", dst, err)
}
if err := tmp.Chmod(perm); err != nil {
tmp.Close()
return fmt.Errorf("chmod temp for %s: %w", dst, err)
}
if err := tmp.Close(); err != nil {
return fmt.Errorf("close temp for %s: %w", dst, err)
}
if err := os.Rename(tmpName, dst); err != nil {
return fmt.Errorf("rename temp to %s: %w", dst, err)
}
return nil
}
View on GitHub (pinned to 2c0912b6ec)
Solutions
- Move the env RootDir (and Hermes homes) to a POSIX-permission filesystem (ext4, xfs, apfs, NTFS via Go's ACL mapping usually works).
- For CIFS mounts, mount with the `noperm`/posix options or relocate the directory.
- If the volume type is fixed and cannot honor 0600, accept that derived configs cannot be written there and use a different location.
- Retry after remounting with permission support.
Defensive patterns
Strategy: validation
Validate before calling
probe, err := os.CreateTemp(dir, ".perm-probe-*")
if err != nil { return err }
defer os.Remove(probe.Name())
probe.Close()
if err := os.Chmod(probe.Name(), 0o600); err != nil {
return fmt.Errorf("filesystem at %s cannot honor chmod — pick another location", dir)
} Try / catch
if err := writeFileAtomic(dst, data, perm); err != nil {
var pe *os.PathError
if errors.As(err, &pe) && strings.Contains(err.Error(), "chmod temp") &&
(errors.Is(pe.Err, syscall.EPERM) || errors.Is(pe.Err, syscall.ENOTSUP)) {
log.Printf("%s does not support permission bits; relocate env root", filepath.Dir(dst))
}
return err
} Prevention
- Do not place env roots on FAT/exFAC or permission-less network mounts.
- Smoke-test the chmod path at daemon start on any new volume type.
When it happens
Trigger: Destination on FAT/exFAT or a network filesystem (CIFS/SMB without POSIX extensions, some NFS configs) where chmod returns EPERM/EINVAL; Windows ACL semantics making Go's Chmod fail; overlayfs edge cases in containers.
Common situations: Env RootDir placed on a Windows share, USB/exFAT drive, or container volume with restricted syscall support; secrets-bearing config written through this path fails closed rather than shipping world-readable.
Related errors
- mint PAT: response missing token
- daemon profile is not resolved yet; token sync skipped
- runtime local skill discovery timed out
- runtime local skill import timed out
- runtime local skill import failed
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/7df62126876dd999.
Report an issue: GitHub.