multica-ai/multica · error

runtime local skill import timed out

Error message

runtime local skill import timed out

What it means

Wrap thrown by prepareHermesHome when writeDerivedHermesEnv fails. This writes the overlay's .env: the source home's .env with any HERMES_HOME assignment stripped, plus a pinned HERMES_HOME appended last so it wins (Hermes loads <HERMES_HOME>/.env with override=True right after profile resolution). The file is always written — even with no source .env — 0600 via atomic replace, because it can hold API-key secrets. A write failure is fatal since an absent .env would let Hermes' project-.env fallback relocate the home and break skill binding and memory isolation.

Source

Thrown at packages/core/runtimes/local-skills.ts:66

  return {
    skills: current.skills ?? [],
    supported: current.supported,
	mcpServers: current.mcp_servers ?? [],
	mcpSupported: current.mcp_supported === true,
  };
}

export async function resolveRuntimeLocalSkillImport(
  runtimeId: string,
  payload: CreateRuntimeLocalSkillImportRequest,
): Promise<RuntimeLocalSkillImportResult> {
  const initial = await api.initiateImportLocalSkill(runtimeId, payload);
  const start = Date.now();
  let current = initial;

  while (current.status === "pending" || current.status === "running") {
    if (Date.now() - start > IMPORT_POLL_TIMEOUT_MS) {
      throw new Error("runtime local skill import timed out");
    }
    await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
    current = await api.getImportLocalSkillResult(runtimeId, initial.id);
  }

  if (current.status === "conflict") {
    if (!current.conflict) {
      throw new Error("runtime local skill import conflict missing details");
    }
    return {
      status: "conflict",
      conflict: current.conflict,
    };
  }

  if (current.status === "failed" || current.status === "timeout") {
    throw new Error(current.error || "runtime local skill import failed");
  }

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Check ownership/permissions of <envRoot>/hermes-home/.env and repair or remove it so the atomic replace can proceed.
  2. Free disk space on the env-root volume.
  3. Ensure env-root is on a POSIX filesystem supporting rename(2).
  4. If reading the source .env is the failing part (see the wrapped 'read shared .env' error), fix that file's permissions first.

Example fix

# before: stale overlay .env owned by root blocks atomic replace
$ ls -l /var/lib/app/envs/task-9/hermes-home/.env
-rw------- 1 root root ...

# after
$ chown daemonuser:daemongroup /var/lib/app/envs/task-9/hermes-home/.env  # or delete it
Defensive patterns

Strategy: try-catch

Validate before calling

envFile := filepath.Join(envRoot, "hermes-home", ".env")
if fi, err := os.Stat(envFile); err == nil && !fi.Mode().IsRegular() {
    return fmt.Errorf("overlay .env path is not a regular file: %s", envFile)
}

Try / catch

if err := prepareHermesHome(...); err != nil {
    if strings.Contains(err.Error(), "derive hermes .env") {
        // check the wrapped error: source read perms (see 'read shared .env') vs overlay write; fix and retry prepare
    }
}

Prevention

When it happens

Trigger: writeDerivedHermesEnv(sharedHome, hermesHome) errors — reading the source .env fails with a non-NotExist error (handled by a narrower wrap), stripping/serialization fails, or the atomic replace into hermes-home fails on permissions or full disk.

Common situations: Overlay .env left owned by a previous daemon user in a recycled env-root; disk full at the moment of the atomic rename; env-root on a filesystem that does not support the rename-based atomic write.

Understand the failure class

Related errors


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/2b3095ac888f78b4. Report an issue: GitHub.