Go's noCopy Marker: How go vet Catches Unsafe Struct Copies
The noCopy marker in Go's sync package isn't a compiler rule—it's a clever hook for go vet's copylocks checker. Here's how it works and how to use it in your own types.

The sync package's structs like sync.Mutex, sync.Once, and sync.Map all contain a field of type noCopy. This marker is an empty struct with two empty methods, Lock and Unlock. It doesn't add any special rule to the Go compiler—you can still copy a sync.Map after use and go build will pass. The warning comes from go vet, specifically its copylocks checker.
The checker's rule is simple: it looks for a type whose pointer implements sync.Locker but whose value does not. For noCopy, the pointer receiver methods make *noCopy implement sync.Locker while the value type doesn't. The checker recursively inspects struct fields, so it finds noCopy inside sync.Map and reports assignment copies lock value to b: sync.Map contains sync.noCopy.
Why does sync.Map need the explicit marker when it already contains a sync.Mutex? Three reasons: it makes the warning clearer, it doesn't depend on internal implementation, and it fixes a false negative. A type like type LocalMutex sync.Mutex loses the Lock/Unlock methods, so the checker would miss it without noCopy in the underlying struct.
You can define your own noCopy type for your packages. Just copy the pattern:
type noCopy struct{}
func (*noCopy) Lock() {}
func (*noCopy) Unlock() {}
type Session struct {
_ noCopy
id string
closed bool
}Note that go test doesn't run copylocks by default. You need to run go vet ./... or go test -vet=copylocks ./... to catch these copies.
What breaks when you ignore the warning? It depends. A copied sync.WaitGroup can cause Wait() to never return, because the counter is copied and Done() only decrements the copy. Copying a mutex can lead to data races and deadlocks.
The noCopy marker was added in 2016 by Aliaksandr Valialkin (VictoriaMetrics CTO) based on a pattern by Russ Cox. It's a clever static-analysis hook, not a runtime safety net.
The noCopy marker doesn't add any special rule to the Go compiler. The warning comes from go vet's copylocks checker, which looks for types whose pointer implements sync.Locker but whose value doesn't.
Source: Phuong Le
Discussion
0 Comments
Be the first to start the discussion.