temporalio/temporal · error
parallelsuite: assertion called on %q after Run() was called
Error message
parallelsuite: assertion called on %q after Run() was called; use the callback parameter's assertions inside Run() instead
What it means
parallelsuite's guardT wraps a testing.T and seals it once Suite.Run() spawns subtests. Any assertion method invoked on the parent guard after Run() started panics, because assertions must use the subtest callback's own t to avoid cross-subtest races.
Source
Thrown at common/testing/parallelsuite/guard.go:20
import (
"fmt"
"sync/atomic"
"testing"
)
// guardT is a [require.TestingT] wrapper that prevents assertions after Run() is called.
//
// Assertions before Run() are allowed; after Run() any assertion panics.
type guardT struct {
*testing.T
name string
hasSubtests atomic.Bool
}
func (g *guardT) Helper() {
if g.hasSubtests.Load() {
panic(fmt.Sprintf(
"parallelsuite: assertion called on %q after Run() was called; "+
"use the callback parameter's assertions inside Run() instead",
g.name,
))
}
g.T.Helper()
}
func (g *guardT) Errorf(format string, args ...any) {
if g.hasSubtests.Load() {
g.Helper() // panics with clear message
}
g.T.Errorf(format, args...)
}
func (g *guardT) FailNow() {
if g.hasSubtests.Load() {
g.Helper() // panics with clear messageView on GitHub (pinned to bde624efd1)
Solutions
- Move the assertion inside the Run() callback and use the callback's t parameter.
- Assert before calling Run(), or capture results and assert within each subtest.
- Restructure shared post-subtest checks so each subtest performs its own assertions on its own t.
Example fix
// before
suite.Run("case", func(t *parallelsuite.T) { ... })
suite.Errorf("done") // panics
// after
suite.Run("case", func(t *parallelsuite.T) {
...
t.Errorf("done")
}) Defensive patterns
Strategy: type-guard
Type guard
func canAssertOnSuite(s *parallelsuite.Suite[X]) bool {
return !s.TB().(*guardT).hasSubtests.Load() // or use suite API before Run()
} Prevention
- Always use the Run() callback's t for assertions.
- Avoid capturing the suite's parent t in long-lived closures or deferred functions.
When it happens
Trigger: Calling s.Errorf(...) (or FailNow, which routes through Helper) on the suite's parent guard after s.Run(name, func(t *parallelsuite.T){...}) has been invoked.
Common situations: Deferring cleanup assertions at suite setup time that fire after Run(); helper methods capturing the suite's t in a closure and calling it inside/after Run(); assertions made between subtests.
Related errors
- parallelsuite: do not call T() after Run(); use the subtest
- len(expectedHistoryEvents) != len(actualHistoryEvents)
- missing RespondWorkflowTaskCompletedRequest return
- history is nil
- history events are empty
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/7e48a24fa56770d6.
Report an issue: GitHub.