multica-ai/multica · error

runtime local skill import failed

Error message

runtime local skill import failed

What it means

Thrown by writeDerivedHermesEnv when reading the shared home's .env fails with any error other than not-exist (a missing file is the normal, tolerated case and yields an empty body). Typical causes are permission denial on the file or an I/O error from the underlying storage; since the derived .env must preserve the source's credentials/settings, an unreadable file is fatal rather than silently dropped.

Source

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

    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");
  }
  if (!current.skill) {
    throw new Error("runtime local skill import did not return a skill");
  }

  return {
    status: current.action === "overwrite" ? "updated" : "created",
    skill: current.skill,
  };
}

export function runtimeLocalSkillsOptions(runtimeId: string | null | undefined) {
  return queryOptions({
    queryKey: runtimeId
      ? runtimeLocalSkillsKeys.forRuntime(runtimeId)
      : runtimeLocalSkillsKeys.all(),
    queryFn: () => resolveRuntimeLocalSkills(runtimeId as string),
    enabled: Boolean(runtimeId),

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Check the file's mode and owner: chmod 0600 <sharedHome>/.env owned by (or readable by) the daemon user.
  2. Ensure every parent directory of the shared home grants execute (x) to the daemon user.
  3. If the path is a directory, remove/rename it so the real .env file can be read.
  4. Repair the underlying storage (disk/NFS) if reads return I/O errors.

Example fix

# before: daemon cannot read the user's .env
$ ls -l /home/user/.hermes/.env
-rw------- 1 otheruser otheruser 120 ...

# after
$ chmod 640 /home/user/.hermes/.env   # or add daemonuser to a readable group
$ chgrp daemonuser /home/user/.hermes/.env
Defensive patterns

Strategy: validation

Validate before calling

src := filepath.Join(sharedHome, ".env")
if fi, err := os.Stat(src); err == nil {
    if !fi.Mode().IsRegular() {
        return fmt.Errorf("%s is not a regular file", src)
    }
    if fi.Mode().Perm()&0o400 == 0 && fi.Mode().Perm()&0o004 == 0 {
        return fmt.Errorf("%s not readable by daemon user", src)
    }
}

Try / catch

if err := writeDerivedHermesEnv(sharedHome, hermesHome); err != nil {
    if strings.Contains(err.Error(), "read shared .env") {
        var pe *os.PathError
        if errors.As(err, &pe) && errors.Is(pe.Err, os.ErrPermission) {
            // fix perms on sharedHome/.env, then re-run prepare
        }
    }
}

Prevention

When it happens

Trigger: os.ReadFile(filepath.Join(sharedHome, ".env")) returns an error where os.IsNotExist(err) is false — mode 0000 or owner-only perms excluding the daemon user, an unreadable directory in the path, or EIO from a failing disk/NFS mount.

Common situations: User's .env created with restrictive perms by a different tool/user than the daemon runs as; shared home on NFS with root-squash; failing disk returning EIO; the .env path being a directory.

Related errors


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