wavetermdev/waveterm · error

failed to write file: %w

Error message

failed to write file: %w

What it means

WriteAppFile in pkg/waveappstore writes a file into the app's directory under ~/waveapps/<ns>/<app>. This error wraps the underlying os.WriteFile failure after the parent directory was already created successfully (waveappstore.go:282-284). It means the path resolved fine but the actual write syscall failed, and the wrapped OS error (permission denied, disk full, is-a-directory, etc.) is in the %w chain.

Source

Thrown at pkg/waveappstore/waveappstore.go:283

		return fmt.Errorf("invalid appId: %w", err)
	}

	appDir, err := GetAppDir(appId)
	if err != nil {
		return err
	}

	filePath, err := validateAndResolveFilePath(appDir, fileName)
	if err != nil {
		return err
	}

	if err := os.MkdirAll(filepath.Dir(filePath), 0755); err != nil {
		return fmt.Errorf("failed to create directory: %w", err)
	}

	if err := os.WriteFile(filePath, contents, 0644); err != nil {
		return fmt.Errorf("failed to write file: %w", err)
	}

	return nil
}

func ReadAppFile(appId string, fileName string) (*FileData, error) {
	if err := ValidateAppId(appId); err != nil {
		return nil, fmt.Errorf("invalid appId: %w", err)
	}

	appDir, err := GetAppDir(appId)
	if err != nil {
		return nil, err
	}

	filePath, err := validateAndResolveFilePath(appDir, fileName)
	if err != nil {
		return nil, err

View on GitHub (pinned to a4447c1563)

Solutions

  1. Inspect the wrapped error with errors.Unwrap or %v on the returned error to get the exact errno (EACCES, ENOSPC, EISDIR).
  2. If permission denied: check ownership/permissions of ~/waveapps/<ns>/<app>/ and chown/chmod back to the current user.
  3. If the target path is a directory, remove or rename the conflicting directory.
  4. If disk full, free space on the home filesystem and retry.
  5. Ensure fileName is a relative path inside the app dir and the appId is valid so the resolved path is the intended one.

Example fix

// before: blindly retrying a failed write
err := waveappstore.WriteAppFile(appId, "app.go", contents)
if err != nil { return err } // opaque

// after: surface and handle the wrapped OS error
if err := waveappstore.WriteAppFile(appId, "app.go", contents); err != nil {
    if errors.Is(err, fs.ErrPermission) {
        return fmt.Errorf("cannot write %s: fix ownership of ~/waveapps", appId)
    }
    if errors.Is(err, fs.ErrExist) {
        return fmt.Errorf("a directory exists at the target path")
    }
    return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: pre-check writability of the target before calling WriteAppFile
func canWrite(appId, fileName string) error {
    dir, err := waveappstore.GetAppDir(appId)
    if err != nil { return err }
    target := filepath.Join(dir, filepath.Clean(fileName))
    if fi, err := os.Stat(target); err == nil && fi.IsDir() {
        return fmt.Errorf("target is a directory: %s", target)
    }
    f, err := os.OpenFile(filepath.Dir(target), os.O_WRONLY, 0)
    if err != nil { return err }
    f.Close()
    return nil
}

Try / catch

err := waveappstore.WriteAppFile(appId, fileName, contents)
if err != nil {
    switch {
    case errors.Is(err, fs.ErrPermission):
        // fix ownership/permissions, prompt user
    case errors.Is(err, fs.ErrExist):
        // directory conflict at target path
    default:
        // surface wrapped errno
    }
}

Prevention

When it happens

Trigger: Calling WriteAppFile (or the WriteAppFileCommand / WriteAppGoFileCommand RPCs) where os.WriteFile fails: target path exists as a directory, the file or parent dir is not writable, the filesystem is read-only or full, or an immutable/locked file is being overwritten.

Common situations: A directory named like the target file exists (e.g. someone created 'app.go/' by accident); ~/waveapps owned by another user after running the terminal with sudo; disk quota exceeded; editing an app while a sync/backup tool holds the file locked on Windows.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/104703cfc3bc8a66. Report an issue: GitHub.