router-for-me/CLIProxyAPI · error

failed to write file: %w

Error message

failed to write file: %w

What it means

writeAuthFile in auth_files_crud.go persists an uploaded auth file with os.WriteFile(dst, data, 0o600) after building the Auth record. If the OS write to auths/<name> fails, it wraps as `failed to write file: %w`. The destination is constrained to h.cfg.AuthDir with a basename, so path traversal is already excluded — this is an environment-level write failure.

Source

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

	if err := h.writeAuthFile(ctx, name, data); err != nil {
		return "", err
	}
	return name, nil
}

func (h *Handler) writeAuthFile(ctx context.Context, name string, data []byte) error {
	dst := filepath.Join(h.cfg.AuthDir, filepath.Base(name))
	if !filepath.IsAbs(dst) {
		if abs, errAbs := filepath.Abs(dst); errAbs == nil {
			dst = abs
		}
	}
	auth, err := h.buildAuthFromFileData(dst, data)
	if err != nil {
		return err
	}
	if errWrite := os.WriteFile(dst, data, 0o600); errWrite != nil {
		return fmt.Errorf("failed to write file: %w", errWrite)
	}
	if err := h.upsertAuthRecord(ctx, auth); err != nil {
		return err
	}
	return nil
}

func requestedAuthFileNamesForDelete(c *gin.Context) ([]string, error) {
	if c == nil {
		return nil, nil
	}
	names := uniqueAuthFileNames(c.QueryArray("name"))
	if len(names) > 0 {
		return names, nil
	}

	body, err := io.ReadAll(c.Request.Body)
	if err != nil {

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Ensure the configured authDir exists and is writable by the proxy process user (mkdir -p auths && chown).
  2. Check disk space and quotas on the authDir filesystem.
  3. On containers, mount auths/ as a writable volume with correct ownership.
  4. Read the wrapped OS error for the precise errno (permission, ENOSPC, EROFS) and address that.

Example fix

# before
$ docker run -v ./auths:/app/auths:ro ...  # read-only mount

# after
$ docker run -v ./auths:/app/auths ...  # writable mount
$ chown -R 1000:1000 ./auths
Defensive patterns

Strategy: validation

Validate before calling

func authDirWritableForWrite(authDir string) bool {
    if err := os.MkdirAll(authDir, 0o755); err != nil { return false }
    probe := filepath.Join(authDir, ".probe")
    ok := os.WriteFile(probe, nil, 0o600) == nil
    _ = os.Remove(probe)
    return ok
}

Type guard

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

Prevention

When it happens

Trigger: authDir does not exist; directory or existing file not writable by the process user; disk full; SELinux denial; container read-only volume; existing file owned by root with 0600 while proxy runs unprivileged.

Common situations: Docker deployments mounting auths/ read-only or as root-owned volume; first run before authDir was created; disk quota exhausted; permission mismatch after migrating hosts.

Related errors


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