Skip to content

go 1.26.2 breaks restic backup (via failing directory metadata reads) on Windows #21791

@jtru

Description

@jtru

Output of restic version

restic 0.18.1-dev (compiled manually) compiled with go1.26.2-X:nodwarf5 on windows/amd64

What backend/service did you use to store the repository?

Local file system, but that is irrelevant.

Problem description / Steps to reproduce

When building current restic master with go 1.26.2 (and potentially also earlier releases after 1.24.0; I have not verified that yet), the resulting executable cannot read extended attributes on directories under Windows, and seems to hang at least minutes (probably indefinitely) when trying to back up any directory.

I verified this behavior under Windows 10 (Windows 21H2 (OS Build 19044.7184)), Windows 11 (Windows 24H2 (OS Build 26100.8246)), and Windows Server 2022 (unknown build info, but up to date). It makes no difference whether or not admin privileges are granted to the restic process, or if VSS/snapshots are used or not. Backing up an individual file (e. g., "C:\foo\bar.txt") does work fine afaict, while including any directory (e. g., "C:\foo") in the backup/snapshot triggers the problem.

The same code compiled with go 1.24.0 as provided by https://beta.restic.net does not suffer this problem. I collected logs from both executables (one built by myself with the more up to date 1.26 toolchain and runtime, one as provided by the latest beta build from today) running on Windows 10 with admin privs below:

Working case (go 1.24.0; abbreviated after a while):

026/05/04 18:58:08 archiver/archiver.go:888    archiver.(*Archiver).Snapshot.func1.1   45      starting snapshot
2026/05/04 18:58:08 archiver/archiver.go:673    archiver.(*Archiver).saveTree   45      / (1 nodes)
2026/05/04 18:58:08 archiver/archiver.go:762    archiver.(*Archiver).dirPathToNode      45      /C, reading dir node data from C:\
2026/05/04 18:58:08 fs/node_windows.go:124      fs.nodeFillExtendedAttributes   45      fillExtendedAttributes(C:\) []
2026/05/04 18:58:08 archiver/archiver.go:673    archiver.(*Archiver).saveTree   45      /C (1 nodes)
2026/05/04 18:58:08 archiver/archiver.go:455    archiver.(*Archiver).save       45      /C/Xgpro target "C:\\Xgpro", previous <nil>
2026/05/04 18:58:08 archiver/archiver.go:576    archiver.(*Archiver).save       45        C:\Xgpro dir
2026/05/04 18:58:08 archiver/archiver.go:311    archiver.(*Archiver).saveDir    45      /C/Xgpro C:\Xgpro
2026/05/04 18:58:08 fs/node_windows.go:124      fs.nodeFillExtendedAttributes   45      fillExtendedAttributes(C:\Xgpro) []
2026/05/04 18:58:08 archiver/archiver.go:455    archiver.(*Archiver).save       45      /C/Xgpro/ATMEGA8_LED target "C:\\Xgpro\\ATMEGA8_LED", previous <nil>
2026/05/04 18:58:08 archiver/archiver.go:576    archiver.(*Archiver).save       45        C:\Xgpro\ATMEGA8_LED dir
2026/05/04 18:58:08 archiver/archiver.go:311    archiver.(*Archiver).saveDir    45      /C/Xgpro/ATMEGA8_LED C:\Xgpro\ATMEGA8_LED
2026/05/04 18:58:08 fs/node_windows.go:124      fs.nodeFillExtendedAttributes   45      fillExtendedAttributes(C:\Xgpro\ATMEGA8_LED) []
2026/05/04 18:58:08 archiver/archiver.go:455    archiver.(*Archiver).save       45      /C/Xgpro/ATMEGA8_LED/ATMEGA8加密实例说明.txt target "C:\\Xgpro\\ATMEGA8_LED\\ATMEGA8加密实例说明.txt", previous <nil>
2026/05/04 18:58:08 archiver/archiver.go:510    archiver.(*Archiver).save       45        C:\Xgpro\ATMEGA8_LED\ATMEGA8加密实例说明.txt regular file
2026/05/04 18:58:08 archiver/file_saver.go:149  archiver.(*fileSaver).saveFile  46      /C/Xgpro/ATMEGA8_LED/ATMEGA8加密实例说明.txt
2026/05/04 18:58:08 archiver/archiver.go:614    archiver.(*Archiver).save       45      return after 0.007
2026/05/04 18:58:08 fs/node_windows.go:124      fs.nodeFillExtendedAttributes   46      fillExtendedAttributes(C:\Xgpro\ATMEGA8_LED\ATMEGA8加密实例说明.txt) []
2026/05/04 18:58:08 archiver/archiver.go:455    archiver.(*Archiver).save       45      /C/Xgpro/ATMEGA8_LED/DDL_source target "C:\\Xgpro\\ATMEGA8_LED\\DDL_source", previous <nil>
2026/05/04 18:58:08 archiver/archiver.go:576    archiver.(*Archiver).save       45        C:\Xgpro\ATMEGA8_LED\DDL_source dir
2026/05/04 18:58:08 archiver/archiver.go:311    archiver.(*Archiver).saveDir    45      /C/Xgpro/ATMEGA8_LED/DDL_source C:\Xgpro\ATMEGA8_LED\DDL_source
2026/05/04 18:58:08 repository/repository.go:380        repository.(*Repository).saveAndEncrypt 32      save id 70316685ff844a9c7cc7a15ee42f9b0f33e7e59d1343625b512740e7c78957a1 (data, 761 bytes)
2026/05/04 18:58:08 fs/node_windows.go:124      fs.nodeFillExtendedAttributes   45      fillExtendedAttributes(C:\Xgpro\ATMEGA8_LED\DDL_source) []
2026/05/04 18:58:08 repository/packer_manager.go:203    repository.(*packerManager).newPacker   32      create new pack
2026/05/04 18:58:08 archiver/archiver.go:455    archiver.(*Archiver).save       45      /C/Xgpro/ATMEGA8_LED/DDL_source/Debug target "C:\\Xgpro\\ATMEGA8_LED\\DDL_source\\Debug", previous <nil>
2026/05/04 18:58:08 repository/packer_manager.go:134    repository.(*packerManager).SaveBlob    32      pack is not full enough (676 bytes)
2026/05/04 18:58:08 archiver/archiver.go:576    archiver.(*Archiver).save       45        C:\Xgpro\ATMEGA8_LED\DDL_source\Debug dir
2026/05/04 18:58:08 archiver/archiver.go:311    archiver.(*Archiver).saveDir    45      /C/Xgpro/ATMEGA8_LED/DDL_source/Debug C:\Xgpro\ATMEGA8_LED\DDL_source\Debug
2026/05/04 18:58:08 fs/node_windows.go:124      fs.nodeFillExtendedAttributes   45      fillExtendedAttributes(C:\Xgpro\ATMEGA8_LED\DDL_source\Debug) []
2026/05/04 18:58:08 archiver/archiver.go:614    archiver.(*Archiver).save       45      return after 0.002
2026/05/04 18:58:08 archiver/archiver.go:455    archiver.(*Archiver).save       45      /C/Xgpro/ATMEGA8_LED/DDL_source/GetSerial.bbs target "C:\\Xgpro\\ATMEGA8_LED\\DDL_source\\GetSerial.bbs", previous <nil>
2026/05/04 18:58:08 archiver/archiver.go:510    archiver.(*Archiver).save       45        C:\Xgpro\ATMEGA8_LED\DDL_source\GetSerial.bbs regular file
2026/05/04 18:58:08 archiver/file_saver.go:149  archiver.(*fileSaver).saveFile  47      /C/Xgpro/ATMEGA8_LED/DDL_source/GetSerial.bbs
2026/05/04 18:58:08 archiver/archiver.go:614    archiver.(*Archiver).save       45      return after 0.006
[...]

Broken case (go 1.26.2):

2026/05/04 18:55:39 archiver/archiver.go:888    archiver.(*Archiver).Snapshot.func1.1   67      starting snapshot
2026/05/04 18:55:39 archiver/archiver.go:673    archiver.(*Archiver).saveTree   67      / (1 nodes)
2026/05/04 18:55:39 archiver/archiver.go:762    archiver.(*Archiver).dirPathToNode      67      /C, reading dir node data from C:\
2026/05/04 18:55:39 fs/node_windows.go:124      fs.nodeFillExtendedAttributes   67      fillExtendedAttributes(C:\) []
2026/05/04 18:55:39 archiver/archiver.go:673    archiver.(*Archiver).saveTree   67      /C (1 nodes)
2026/05/04 18:55:39 archiver/archiver.go:455    archiver.(*Archiver).save       67      /C/Xgpro target "C:\\Xgpro", previous <nil>
2026/05/04 18:55:39 archiver/archiver.go:576    archiver.(*Archiver).save       67        C:\Xgpro dir
2026/05/04 18:55:39 archiver/archiver.go:311    archiver.(*Archiver).saveDir    67      /C/Xgpro C:\Xgpro
2026/05/04 18:55:39 fs/node_windows.go:124      fs.nodeFillExtendedAttributes   67      fillExtendedAttributes(C:\Xgpro) []
2026/05/04 18:55:54 restic/cleanup.go:27        main.cleanupHandler     20      signal interrupt received, cleaning up
2026/05/04 18:55:54 repository/lock.go:207      repository.(*locker).monitorLockRefresh 38      terminate expiry monitoring
2026/05/04 18:55:54 repository/lock.go:143      repository.(*locker).refreshLocks       37      terminate
2026/05/04 18:55:54 repository/lock.go:131      repository.(*locker).refreshLocks.func1 37      unlocking repository with lock PID 5644 on gamebro by GAMEBRO\Johannes (UID 0, GID 0)
lock was created at 2026-05-04 18:55:39 (15.1930195s ago)
storage ID 615d57dc
2026/05/04 18:55:54 cache/backend.go:40 cache.(*Backend).Remove 37      cache Remove(<lock/615d57dc9e>)
2026/05/04 18:55:54 logger/log.go:38    logger.(*Backend).Remove        37      Remove(<lock/615d57dc9e>)
2026/05/04 18:55:54 logger/log.go:40    logger.(*Backend).Remove        37        remove err <nil>
2026/05/04 18:56:16 restic/main.go:177  main.main       1       main []string{"restic", "version"}
2026/05/04 18:56:16 restic/main.go:178  main.main       1       restic 0.18.1-dev (compiled manually) compiled with go1.26.2-X:nodwarf5 on windows/amd64
2026/05/04 18:56:16 restic/cleanup.go:42        main.Exit       1       exiting with status code 0

The equivalent of the signal handler under Windows does not make the restic process terminate under these conditions, and I have to kill the process using Task Manager.

To reproduce, it should be enough to build master with go 1.26.2, and try a trivial backup operation under Windows that does involve at least one directory.

Expected behavior

restic should not stall for at least minutes (or maybe indefinitely) when trying to back up / read metadata from directories under Windows.

Actual behavior

Backup operations involving at least one directory under Windows fail to complete.

Do you have any idea what may have caused this?

I haven't looked at golang changes between 1.24 and 1.26 yet, but it sure looks like this could be a proper go runtime bug. The calls logged via DEBUG_FILES are identical for both binaries, so something "underneath" restic seems like the likely culprit of this disruptive change in behavior.

Did restic help you today? Did it make you happy in any way?

restic is one of the neatest pieces of software written in this millenium :)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions