router-for-me/CLIProxyAPI · error

failed to remove file: %w

Error message

failed to remove file: %w

What it means

deleteAuthFileByName removes the target file from disk with os.Remove after resolving it under authDir (or the auth record's stored `path`). If Remove fails and it is not a not-exist case (which maps to 404 errAuthFileNotFound), the error wraps as `failed to remove file: %w` with HTTP 500. Causes are environmental: permission denied on file/dir, read-only filesystem, or the file being a non-empty directory.

Source

Thrown at internal/api/handlers/management/auth_files_crud.go:368

	if targetAuth := h.findAuthForDelete(name); targetAuth != nil {
		if !isPluginVirtualSourceDelete(name, targetAuth) {
			return filepath.Base(name), http.StatusConflict, errPluginVirtualAuth
		}
		targetID = strings.TrimSpace(targetAuth.ID)
		if path := strings.TrimSpace(authAttribute(targetAuth, "path")); path != "" {
			targetPath = path
		}
	}
	if !filepath.IsAbs(targetPath) {
		if abs, errAbs := filepath.Abs(targetPath); errAbs == nil {
			targetPath = abs
		}
	}
	if errRemove := os.Remove(targetPath); errRemove != nil {
		if os.IsNotExist(errRemove) {
			return filepath.Base(name), http.StatusNotFound, errAuthFileNotFound
		}
		return filepath.Base(name), http.StatusInternalServerError, fmt.Errorf("failed to remove file: %w", errRemove)
	}
	if errDeleteRecord := h.deleteTokenRecord(ctx, targetPath); errDeleteRecord != nil {
		return filepath.Base(name), http.StatusInternalServerError, errDeleteRecord
	}
	h.removeAuthsForPath(ctx, targetPath, targetID)
	return filepath.Base(name), http.StatusOK, nil
}

func isPluginVirtualSourceDelete(name string, auth *coreauth.Auth) bool {
	if !coreauth.IsPluginVirtualAuth(auth) {
		return true
	}
	sourcePath := strings.TrimSpace(authAttribute(auth, coreauth.AttributeVirtualSource))
	if sourcePath == "" {
		sourcePath = strings.TrimSpace(authAttribute(auth, "path"))
	}
	if sourcePath == "" {
		return false

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Read the wrapped OS error: EACCES -> fix ownership/permissions of the file and authDir; EROFS -> remount volume writable.
  2. In containers, mount auths/ writable and owned by the process user.
  3. Verify the auth record's `path` attribute points to a location the proxy may delete.
  4. Retry after fixing permissions — the record cleanup (deleteTokenRecord, removeAuthsForPath) runs only after successful removal.

Example fix

# before: root-owned auth file, proxy runs as app user
$ ls -l auths/x.json  # -rw------- root root

# after
$ chown $(id -u app):$(id -g app) auths/x.json && chmod u+rw auths/x.json
Defensive patterns

Strategy: validation

Validate before calling

func canDeleteAuthFile(path string) bool {
    info, err := os.Stat(path)
    if err != nil { return false }
    // writable check: try opening for write
    f, err := os.OpenFile(path, os.O_WRONLY, 0o600)
    if err != nil { return false }
    _ = f.Close()
    return true
}

Type guard

func isRemoveFailure(err error) bool {
    return err != nil && strings.Contains(err.Error(), "failed to remove file")
}

Prevention

When it happens

Trigger: authDir file owned by root while the proxy runs unprivileged; auths/ mounted read-only in a container; file has immutable attribute; targetPath resolved from the auth record's `path` attribute points somewhere the process cannot write; attempting to remove a directory with entries.

Common situations: Docker auths volumes owned by root; SELinux/AppArmor policies; files created by a previous run under a different user; NFS mounts with root_squash.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/3393227ab03340b7. Report an issue: GitHub.