wavetermdev/waveterm · error

failed to write %s: %w

Error message

failed to write %s: %w

What it means

After marshaling, WriteAppSecretBindings writes the JSON to SecretBindingsFileName inside the app's directory with os.WriteFile (mode 0644). If the file cannot be written, the OS error is wrapped as 'failed to write <file>: %w'. This indicates a filesystem-level problem, not a data problem.

Source

Thrown at pkg/waveappstore/waveappstore.go:798

	}

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

	if bindings == nil {
		bindings = make(map[string]string)
	}

	data, err := json.MarshalIndent(bindings, "", "  ")
	if err != nil {
		return fmt.Errorf("failed to marshal bindings: %w", err)
	}

	bindingsPath := filepath.Join(appDir, SecretBindingsFileName)
	if err := os.WriteFile(bindingsPath, data, 0644); err != nil {
		return fmt.Errorf("failed to write %s: %w", SecretBindingsFileName, err)
	}

	return nil
}

func BuildAppSecretEnv(appId string, manifest *wshrpc.AppManifest, bindings map[string]string) (map[string]string, error) {
	if manifest == nil {
		return make(map[string]string), nil
	}

	if bindings == nil {
		bindings = make(map[string]string)
	}

	secretEnv := make(map[string]string)

	for secretName, secretMeta := range manifest.Secrets {
		boundSecretName, hasBinding := bindings[secretName]

View on GitHub (pinned to a4447c1563)

Solutions

  1. Read the wrapped %w error (EACCES/ENOENT/ENOSPC/ELOCKED) to identify the exact OS cause
  2. Ensure the app directory exists (recreate via the install flow or os.MkdirAll) before writing
  3. Fix permissions on the app store directory or run as the owning user
  4. Free disk space if the error indicates ENOSPC
  5. Retry if the file was transiently locked by another process

Example fix

// before
err := waveappstore.WriteAppSecretBindings(appId, bindings) // ENOENT
// after
appDir, _ := waveappstore.GetAppDir(appId)
if err := os.MkdirAll(appDir, 0755); err != nil {
    return err
}
err = waveappstore.WriteAppSecretBindings(appId, bindings)
Defensive patterns

Strategy: try-catch

Validate before calling

appDir, err := waveappstore.GetAppDir(appId)
if err != nil { return err }
if info, err := os.Stat(appDir); err != nil || !info.IsDir() {
    if mkErr := os.MkdirAll(appDir, 0755); mkErr != nil { return mkErr }
}
if err := unix.Access(appDir, unix.W_OK); err != nil { return fmt.Errorf("app dir not writable: %w", err) }

Type guard

func dirWritable(path string) bool {
    info, err := os.Stat(path)
    return err == nil && info.IsDir() && unix.Access(path, unix.W_OK) == nil
}

Try / catch

if err := waveappstore.WriteAppSecretBindings(appId, bindings); err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) {
        log.Printf("write failed at %s: %v", perr.Path, perr.Err)
    }
    return err
}

Prevention

When it happens

Trigger: os.WriteFile fails because the app directory does not exist, the process lacks write permission on the file or directory, the disk is full, the path is read-only, or on Windows the file is locked by another process.

Common situations: App store directory was deleted or never created (GetAppDir succeeded but dir was removed concurrently); running with a different user/permissions than the one that owns ~/.waveterm; read-only home mount; antivirus/indexer holding the file on Windows; ENOSPC on a full disk.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


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