stretchr/testify · error

test failed and t is missing `FailNow()`

Error message

test failed and t is missing `FailNow()`

What it means

Panicked by FailNow (assert/assertions.go:346) when the passed TestingT does not implement the failNower interface (i.e. lacks a FailNow() method). The TestingT interface could not be extended with FailNow without breaking backwards compatibility (issue #263), so testify falls back to a panic. This typically surfaces when require-package assertions are used against a custom testing double that only implements Errorf/Logf.

Source

Thrown at assert/assertions.go:361

}

// FailNow fails test
func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
	if h, ok := t.(tHelper); ok {
		h.Helper()
	}
	Fail(t, failureMessage, msgAndArgs...)

	// We cannot extend TestingT with FailNow() and
	// maintain backwards compatibility, so we fallback
	// to panicking when FailNow is not available in
	// TestingT.
	// See issue #263

	if t, ok := t.(failNower); ok {
		t.FailNow()
	} else {
		panic("test failed and t is missing `FailNow()`")
	}
	return false
}

// Fail reports a failure through
func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
	if h, ok := t.(tHelper); ok {
		h.Helper()
	}
	content := []labeledContent{
		{"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")},
		{"Error", failureMessage},
	}

	// Add test name if the Go version supports it
	if n, ok := t.(interface {
		Name() string
	}); ok {

View on GitHub (pinned to 001eb7946b)

Solutions

  1. Make your custom TestingT implement FailNow() (delegating to embedded *testing.T or calling runtime.Goexit).
  2. Use assert.* (which only needs Errorf) instead of require.* when your fake lacks FailNow.
  3. Embed *testing.T in your wrapper so it inherits FailNow for free.

Example fix

// before
type myT struct{ log bytes.Buffer }
func (m *myT) Errorf(f string, a ...any) { /* ... */ }
// require.True(myT{}, x) -> panic
// after
func (m *myT) FailNow() { runtime.Goexit() }
Defensive patterns

Strategy: type-guard

Validate before calling

func implementsFailNow(t assert.TestingT) bool {
    _, ok := t.(interface{ FailNow() })
    return ok
}
// before require.X: assert.True(t, implementsFailNow(tt))

Type guard

func hasFailNow(t assert.TestingT) bool {
    _, ok := t.(interface{ FailNow() })
    return ok
}

Try / catch

// Either implement FailNow or fall back to assert.*:
if !hasFailNow(tt) {
    assert.True(tt, cond) // assert.* needs only Errorf
} else {
    require.True(tt, cond)
}

Prevention

When it happens

Trigger: Passing a custom TestingT (e.g. a fake test reporter, a *bytes.Buffer wrapper, or a third-party test harness) to assert.FailNow or any require.* function, where that type implements Errorf but not FailNow. Also passing a plain *testing.TB value at the interface level in an older code path.

Common situations: Using require inside a custom assertion helper that accepts a minimal interface; wrapping *testing.T in a struct that forwards Errorf but forgets FailNow; using testify with a non-testing.T test runner (e.g. Ginkgo or a custom harness).

Related errors


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