chenhg5/cc-connect · error

read Agy config directory %s: %w

Error message

read Agy config directory %s: %w

What it means

mirrorDirectoryEntries wraps any error from os.ReadDir on the antigravity ('Agy') source config directory. It is thrown when the directory exists but cannot be read (permissions, I/O error, or source is a file, not a directory). A non-existent directory is intentionally treated as success (returns nil), so this error indicates the directory exists but is unreadable.

Source

Thrown at agent/antigravity/permission_bridge.go:172

	data, err := json.MarshalIndent(hooks, "", "  ")
	if err != nil {
		return "", fmt.Errorf("marshal Agy hooks overlay: %w", err)
	}
	data = append(data, '\n')
	if err := os.WriteFile(filepath.Join(overlayConfigDir, "hooks.json"), data, 0o600); err != nil {
		return "", fmt.Errorf("write Agy hooks overlay: %w", err)
	}
	return overlayConfigRoot, nil
}

func mirrorDirectoryEntries(sourceDir, targetDir string, skip map[string]bool) error {
	entries, err := os.ReadDir(sourceDir)
	if os.IsNotExist(err) {
		return nil
	}
	if err != nil {
		return fmt.Errorf("read Agy config directory %s: %w", sourceDir, err)
	}
	for _, entry := range entries {
		if skip[entry.Name()] {
			continue
		}
		source := filepath.Join(sourceDir, entry.Name())
		target := filepath.Join(targetDir, entry.Name())
		if err := os.Symlink(source, target); err != nil {
			return fmt.Errorf("link Agy config %s: %w", source, err)
		}
	}
	return nil
}

func shellQuote(value string) string {
	return "'" + strings.ReplaceAll(value, "'", "'\"'\"'") + "'"
}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check the directory is readable by the current user: ls -la <dir> and fix ownership/permissions (chmod/chown).
  2. Verify the path is actually a directory, not a file: file <dir>.
  3. If the directory should be optional/empty, ensure it exists with correct permissions or remove the stale file so IsNotExist handling applies.
  4. Inspect the wrapped cause (%w) in the message for the underlying OS error.

Example fix

// before: source is a stale file
$ rm ~/.antigravity && mkdir ~/.antigravity
// after
$ mkdir -p ~/.antigravity && chmod 700 ~/.antigravity
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(sourceDir)
if err != nil || !info.IsDir() {
    // directory missing or not a directory — fix perms or recreate
}
if info != nil && info.IsDir() {
    if f, err := os.Open(sourceDir); err != nil { /* unreadable */ } else { f.Close() }
}

Try / catch

if err := createAgyConfigOverlay(...); err != nil && strings.HasPrefix(err.Error(), "read Agy config directory") {
    slog.Warn("agy config dir unreadable, skipping overlay", "err", err)
}

Prevention

When it happens

Trigger: os.ReadDir(sourceDir) fails with an error that is not os.IsNotExist while creating the agy config overlay via createAgyConfigOverlay. E.g. the source dir exists but the process lacks read permission, the path is a regular file, or a disk I/O error occurs.

Common situations: Running cc-connect as a user that cannot read ~/.antigravity (or similar) config owned by another user; a stale file replaced the config directory; NFS/readonly filesystem failures.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/467387e6bbc5f34b. Report an issue: GitHub.