wavetermdev/waveterm · error

failed to read backup metadata: %w

Error message

failed to read backup metadata: %w

What it means

RestoreBackup derives the metadata sidecar path by replacing the .bak suffix with .json and reads it. This error wraps os.ReadFile failing on that .json file; without metadata (full path and permissions) the restore cannot proceed safely.

Source

Thrown at pkg/filebackup/filebackup.go:99

	err = os.WriteFile(metadataPath, metadataJSON, 0600)
	if err != nil {
		return "", fmt.Errorf("failed to write backup metadata: %w", err)
	}

	return backupPath, nil
}

func RestoreBackup(backupFilePath string, restoreToFileName string) error {
	backupData, err := os.ReadFile(backupFilePath)
	if err != nil {
		return fmt.Errorf("failed to read backup file: %w", err)
	}

	metadataPath := backupFilePath[:len(backupFilePath)-4] + ".json"
	metadataData, err := os.ReadFile(metadataPath)
	if err != nil {
		return fmt.Errorf("failed to read backup metadata: %w", err)
	}

	var metadata BackupMetadata
	err = json.Unmarshal(metadataData, &metadata)
	if err != nil {
		return fmt.Errorf("failed to unmarshal backup metadata: %w", err)
	}

	if metadata.FullPath != restoreToFileName {
		return fmt.Errorf("backup metadata mismatch: expected %s, got %s", restoreToFileName, metadata.FullPath)
	}

	var perm os.FileMode
	_, err = fmt.Sscanf(metadata.Perm, "%o", &perm)
	if err != nil {
		return fmt.Errorf("failed to parse file permissions: %w", err)
	}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Verify the .json sidecar exists next to the .bak file (same base name) before restoring.
  2. If the sidecar is gone, locate another backup of the same file in the dated directories that has both .bak and .json.
  3. Avoid copying/moving .bak files without their .json sidecars.
  4. Check cleanup scripts or manual deletions that remove .json files independently.

Example fix

// before
os.Remove(backupPath + ".json") // 'cleanup' breaks restore
// after
// keep .bak and .json together: remove by shared base name
os.Remove(strings.TrimSuffix(backupPath, ".bak") + ".json") // only when removing both
Defensive patterns

Strategy: validation

Validate before calling

metaPath := strings.TrimSuffix(backupFilePath, ".bak") + ".json"
if _, err := os.Stat(metaPath); err != nil {
    return fmt.Errorf("metadata sidecar %s missing; backup pair incomplete", metaPath)
}

Try / catch

err := filebackup.RestoreBackup(backupPath, targetPath)
if err != nil {
    if strings.Contains(err.Error(), "read backup metadata") {
        return fmt.Errorf("backup pair incomplete (.json sidecar missing): %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: The paired <name>.<hash>.<uuid>.json file is missing (deleted individually, partial backup from error 703 scenario, or a .bak file passed without its sidecar ever having been written).

Common situations: A prior backup half-failed leaving an orphan .bak; users or cleanup scripts deleting *.json files; restoring a .bak copied elsewhere without its sidecar.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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