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

  1. Enter the suite via suite.Run(t, &MySuite{}) so SetT runs first; Assert() is then safe inside SetupSuite/BeforeTest/Test*/TearDown.
  2. If you cannot use suite.Run, call s.SetT(t) manually before any Assert()/Require() call.
  3. Pass the suite by pointer (&MySuite{}); never copy a suite value, since SetT mutates fields the copies won't see.
  4. 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

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


AI-assisted analysis of stretchr/testify@001eb7946b (2026-08-04). Data as JSON: /data/errors/51df680b60d86e66.json. Report an issue: GitHub.