restic/restic · error

error parsing generic attribute for: %s : %v

Error message

error parsing generic attribute for: %s : %v

What it means

nodeRestoreGenericAttributes (Windows) converts the node's stored generic attributes to Windows attributes via GenericAttributesToOSAttrs and wraps a parse failure. The parse step decodes each generic attribute's JSON payload (creation time, file attributes, security descriptor) into the typed WindowsAttributes struct, so failure means the stored data for an attribute did not match the expected type. Unlike the per-attribute restore failures below, a parse error aborts generic attribute restoration for this node entirely.

Source

Thrown at internal/fs/node_windows.go:198

			eas = append(eas, extendedAttribute{Name: oldEA.Name, Value: nil})
		}
	}

	if err = fsetEA(fileHandle, eas); err != nil {
		return errors.Errorf("set EA failed for path %v, with: %v", path, err)
	}
	return nil
}

// restoreGenericAttributes restores generic attributes for Windows
func nodeRestoreGenericAttributes(node *data.Node, path string, warn func(msg string)) (err error) {
	if len(node.GenericAttributes) == 0 {
		return nil
	}
	var errs []error
	windowsAttributes, unknownAttribs, err := genericAttributesToWindowsAttrs(node.GenericAttributes)
	if err != nil {
		return fmt.Errorf("error parsing generic attribute for: %s : %v", path, err)
	}
	if windowsAttributes.CreationTime != nil {
		if err := restoreCreationTime(path, windowsAttributes.CreationTime); err != nil {
			errs = append(errs, fmt.Errorf("error restoring creation time for: %s : %v", path, err))
		}
	}
	if windowsAttributes.FileAttributes != nil {
		if err := restoreFileAttributes(path, windowsAttributes.FileAttributes); err != nil {
			errs = append(errs, fmt.Errorf("error restoring file attributes for: %s : %v", path, err))
		}
	}
	if windowsAttributes.SecurityDescriptor != nil {
		if err := setSecurityDescriptor(path, windowsAttributes.SecurityDescriptor); err != nil {
			errs = append(errs, fmt.Errorf("error restoring security descriptor for: %s : %v", path, err))
		}
	}

	data.HandleUnknownGenericAttributesFound(unknownAttribs, warn)

View on GitHub (pinned to a80be1478a)

Solutions

  1. Run `restic check --read-data` to rule out repository corruption.
  2. Restore with a restic version at least as new as the one that created the snapshot (generic attribute formats evolved across 0.16/0.17).
  3. If the attributes are not needed, restore without generic attributes (restic skips them when absent; a parse failure only loses metadata, not file contents).
  4. Re-create the snapshot with the current restic version if the source data is still available.
Defensive patterns

Strategy: fallback

Validate before calling

import "encoding/json"

// best-effort pre-check that stored generic attributes decode:
func genericAttrsParseable(raw map[data.GenericAttributeType]json.RawMessage) bool {
	for k, v := range raw {
		if !json.Valid(v) {
			_ = k
			return false
		}
	}
	return true
}

Try / catch

err := nodeRestoreGenericAttributes(node, path, warn)
if err != nil {
	// contents already restored; only Windows metadata is lost
	warnf("generic attributes for %s skipped: %v", path, err)
}

Prevention

When it happens

Trigger: The snapshot's node.GenericAttributes contains a Windows attribute whose JSON payload is not decodable into the expected Go type (e.g. creation time stored as a string instead of a number after a schema change), or a value out of range (file attribute constant that overflows the destination type). Corrupted snapshot JSON from repo bit rot or a hand-edited snapshot produces the same error.

Common situations: Snapshots created by an older/newer restic version whose generic attribute encoding differs; repo data corruption (run restic check); snapshots restored after partial memory or disk failures during backup.

Related errors


AI-assisted analysis of restic/restic@a80be1478a (2026-08-15). Data as JSON: /api/errors/edd71d5832300ac3. Report an issue: GitHub.