stretchr/testify · error
'Assert' must not be called before 'Run' or 'SetT'
Error message
'Assert' must not be called before 'Run' or 'SetT'
What it means
suite.Assert() (suite/suite.go:75-82) returns the embedded *assert.Assertions handle allocated in SetT (suite.go:42-48). It panics with this message when Assert() is called on a suite whose SetT has not run — i.e. suite.Assertions is still nil. The library panics here (rather than returning nil) to surface the lifecycle violation at the call site instead of letting it become an opaque nil-deref later. It is the assert-side twin of the Require() guard.
Source
Thrown at suite/suite.go:79
panic("'Require' must not be called before 'Run' or 'SetT'")
}
return suite.require
}
// Assert returns an assert context for suite. Normally, you can call:
//
// suite.NoError(err)
//
// But for situations where the embedded methods are overridden (for example,
// you might want to override assert.Assertions with require.Assertions), this
// method is provided so you can call:
//
// suite.Assert().NoError(err)
func (suite *Suite) Assert() *assert.Assertions {
suite.mu.Lock()
defer suite.mu.Unlock()
if suite.Assertions == nil {
panic("'Assert' must not be called before 'Run' or 'SetT'")
}
return suite.Assertions
}
func recoverAndFailOnPanic(t *testing.T) {
t.Helper()
r := recover()
failOnPanic(t, r)
}
func failOnPanic(t *testing.T, r interface{}) {
t.Helper()
if r != nil {
t.Errorf("test panicked: %v\n%s", r, debug.Stack())
t.FailNow()
}
}
View on GitHub (pinned to 001eb7946b)
Solutions
- Enter the suite via suite.Run(t, &MySuite{}) so SetT runs first; Assert() is then safe inside SetupSuite/BeforeTest/Test*/TearDown.
- If you cannot use suite.Run, call s.SetT(t) manually before any Assert()/Require() call.
- Pass the suite by pointer (&MySuite{}); never copy a suite value, since SetT mutates fields the copies won't see.
- Avoid calling Assert() from goroutines or helpers that may execute before SetT; pass the suite pointer in after initialization.
Example fix
// before
func TestBar(t *testing.T) {
s := MySuite{} // value, never Run
s.Assert().Equal(1, 1) // panic: Assert before Run/SetT
}
// after
func TestBar(t *testing.T) {
suite.Run(t, &MySuite{}) // pointer; SetT populates Assertions
}
func (s *MySuite) TestThing() { s.Assert().Equal(1, 1) } Defensive patterns
Strategy: validation
Validate before calling
// Assert() is only safe after SetT populated suite.Assertions;
// use T() as the public readiness probe.
func safeAssert(s *suite.Suite) (*assert.Assertions, error) {
if s.T() == nil {
return nil, errors.New("suite not initialized: call suite.Run or SetT first")
}
return s.Assert(), nil
} Type guard
// Narrow on the readiness signal before any embedded-method override path.
func assertReady(s TestingSuite) bool {
type tGetter interface{ T() *testing.T }
g, ok := s.(tGetter)
return ok && g.T() != nil
}
// usage: if !assertReady(s) { t.Fatal("start suite with suite.Run(t, &MySuite{})") } Try / catch
// Wrap overrides that call Assert() so a lifecycle slip becomes a clear failure.
func safeAssertCall(t *testing.T, s *MySuite, fn func(*assert.Assertions)) {
defer func() {
if r := recover(); r != nil {
t.Fatalf("Assert misuse: %v\nEnsure the suite is started with suite.Run(t, &MySuite{}).", r)
}
}()
fn(s.Assert())
} Prevention
- Enter the suite only through suite.Run(t, &MySuite{}); do not register suite methods via t.Run.
- Pass &MySuite{} (pointer); copying a suite value discards SetT's write to Assertions.
- When overriding embedded assert.Assertions (e.g. to swap for require), still rely on SetT having run; do not assume the field is populated outside the lifecycle.
- Keep Assert()/Require() calls inside Setup*/BeforeTest/Test*/AfterTest/TearDown* hooks, where SetT is guaranteed.
When it happens
Trigger: Calling suite.Assert() (or this.Assert() on an embedded Suite) before suite.Run(t, &s) or an explicit SetT(t). Concretely: (a) instantiating &MySuite{} and invoking methods directly in a t.Run-registered closure instead of via suite.Run; (b) calling Assert() from SetupAllSuite when the suite was registered without going through suite.Run; (c) a suite embedded by value or copied so SetT's write to suite.Assertions never reaches the receiver the test reads; (d) overriding embedded assert.Assertions and forgetting that Assert() still depends on SetT having populated it.
Common situations: Ad-hoc suite usage where the author wraps t.Run themselves and bypasses suite.Run; refactoring a test to embed suite.Suite and calling s.Assert() in a helper invoked from TestMain; copying a suite value (e.g. *s = *original) before Run; embedding suite.Suite as a value field rather than pointer, so SetT's assignment is lost on the next receiver copy.
Related errors
- 'Require' must not be called before 'Run' or 'SetT'
- assert: arguments: Bool(%d) failed because object wasn't cor
- test failed and t is missing `FailNow()`
- Reset() is deprecated
- Copy() is deprecated
AI-assisted analysis of stretchr/testify@001eb7946b (2026-08-04).
Data as JSON: /data/errors/51df680b60d86e66.json.
Report an issue: GitHub.