multica-ai/multica · error · Error
daemon profile is not resolved yet; token sync skipped
Error message
daemon profile is not resolved yet; token sync skipped
What it means
Thrown by prepareHermesHome when os.Chmod(hermesHome, 0o700) fails after MkdirAll. The chmod is intentional on reuse: MkdirAll leaves an existing directory's mode alone, and the derived config written into the overlay can hold inline api_key secrets, so perms are re-tightened every prepare. A chmod failure means the daemon cannot guarantee the overlay is private, so it fails the task.
Source
Thrown at apps/desktop/src/main/daemon-manager.ts:656
* id matches the caller, reuse it — minting fresh on every launch would
* accumulate garbage in the user's tokens page.
* - On user mismatch (or first run) call POST /api/tokens with the JWT to
* mint a fresh PAT, overwriting any stale cached PAT. This is the critical
* path: without it, a previous user's PAT would be used by a new session.
* - If the caller happens to pass a PAT directly, write it through.
* - When we mint fresh and a daemon is already running, restart it so the
* new credentials take effect (the Go daemon reads config at startup).
*/
async function syncToken(
tokenFromRenderer: string,
userId: string,
): Promise<void> {
const active = await ensureActiveProfile();
if (!active) {
// Writing here would land the token and server_url in the user's default
// CLI config. The renderer awaits setTargetApiUrl before calling this, so
// reaching this branch is a real error rather than a normal startup race.
throw new Error("daemon profile is not resolved yet; token sync skipped");
}
const config = await readProfileConfig(active.name);
const previousUserId = await readProfileUserId(active.name);
const userChanged = Boolean(previousUserId) && previousUserId !== userId;
const sameUserWithCachedPat =
!userChanged &&
previousUserId === userId &&
typeof config.token === "string" &&
config.token.startsWith("mul_");
let finalToken: string;
if (tokenFromRenderer.startsWith("mul_")) {
finalToken = tokenFromRenderer;
} else if (sameUserWithCachedPat) {
finalToken = config.token as string;
} else {
try {
finalToken = await mintPat(tokenFromRenderer);View on GitHub (pinned to 2c0912b6ec)
Solutions
- chown the existing hermes-home (and the env-root) to the daemon's current user, then retry the task.
- If chmod is unsupported by the mount, move env-roots to a POSIX-compliant local filesystem.
- Ensure only one daemon/GC process operates on an env-root at a time to rule out concurrent deletion.
- As a last resort remove the stale per-task env-root so prepare recreates it fresh with correct ownership.
Example fix
# before: overlay owned by old daemon user → chmod fails $ ls -ld /var/lib/app/envs/task-9/hermes-home drwxr-xr-x 1 olduser olduser ... # after $ chown -R daemonuser:daemongroup /var/lib/app/envs/task-9
Defensive patterns
Strategy: try-catch
Validate before calling
if fi, err := os.Stat(hermesHome); err == nil {
if stat, ok := fi.Sys().(*syscall.Stat_t); ok && uint(stat.Uid) != os.Getuid() {
return fmt.Errorf("hermes-home owned by uid %d, daemon runs as %d — chown first", stat.Uid, os.Getuid())
}
} Try / catch
if err := prepareHermesHome(...); err != nil {
if strings.Contains(err.Error(), "chmod hermes-home dir") {
// ownership mismatch or unsupported fs: chown tree or move env-root to local POSIX disk
}
} Prevention
- Run the daemon under one stable UID across restarts.
- Keep env-roots on local filesystems that support chmod.
- On daemon user changes, chown all existing env-roots as part of migration.
When it happens
Trigger: prepareHermesHome reuses an existing hermes-home whose owner is not the daemon user (chmod requires ownership or CAP_FOWNER), or the filesystem does not support chmod (some FUSE/NFS mounts), or the dir was removed concurrently between MkdirAll and Chmod.
Common situations: Daemon restarted under a different UID while old task env-roots persist; env-root on NFS with root-squash mapping; a concurrent GC deleting the env-root mid-prepare.
Related errors
- mint PAT: response missing token
- runtime local skill discovery timed out
- runtime local skill import timed out
- runtime local skill import failed
- mint PAT: target API URL not set
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/b5e7c48b90077983.
Report an issue: GitHub.