temporalio/temporal · error
parallelsuite: do not call T() after Run(); use the subtest
Error message
parallelsuite: do not call T() after Run(); use the subtest callback's parameter instead
What it means
Suite.T() returns the parent *testing.T but is sealed once Run() has been called, at which point subtests receive their own t. Calling T() after Run() panics to prevent using the parent handle concurrently with running subtests, which would be a data race / invalid test failure reporting.
Source
Thrown at common/testing/parallelsuite/suite.go:103
g.hasSubtests.Store(false)
s.runParallel = parallel
s.ctx = ctx
if s.runParallel {
t.Parallel() //nolint:testifylint // parallelsuite intentionally supports parallel tests
}
if assertT == nil {
assertT = g
}
s.assertT = assertT
s.Assertions = require.New(assertT)
s.ProtoAssertions = protorequire.New(assertT)
s.HistoryRequire = historyrequire.New(assertT)
}
// T returns the *testing.T, panicking if the guard has been sealed.
func (s *Suite[T]) T() *testing.T {
if s.guardT.hasSubtests.Load() {
panic("parallelsuite: do not call T() after Run(); use the subtest callback's parameter instead")
}
return s.guardT.T
}
// TB returns the underlying test handle.
func (s *Suite[T]) TB() testing.TB {
return s.T()
}
// Require returns assertions bound to the active test or await attempt.
func (s *Suite[T]) Require() *require.Assertions {
return s.Assertions
}
// AssertionT returns the active assertion target.
func (s *Suite[T]) AssertionT() require.TestingT {
return s.assertT
}View on GitHub (pinned to bde624efd1)
Solutions
- Pass the subtest callback's t parameter into any goroutine/helper needing a test handle instead of calling s.T().
- Move T()/Context()/Awaitf() calls to before Run() if they belong to setup.
- Use s.TB() or other unsealed accessors if only a testing.TB is needed and permitted.
Example fix
// before
suite.Run("case", func(t *parallelsuite.T) { ... })
tt := suite.T() // panics
// after
suite.Run("case", func(t *parallelsuite.T) {
tt := t.T()
...
}) Defensive patterns
Strategy: type-guard
Type guard
// inside a Run callback, use the parameter instead of s.T():
suite.Run("case", func(t *parallelsuite.T) {
tt := t.T() // safe
_ = tt
}) Prevention
- Call s.T()/Context()/Awaitf only during setup, before Run().
- Pass the subtest t into spawned goroutines that need test APIs.
When it happens
Trigger: Calling s.T() (directly or via TB, Context, Awaitf, AwaitTruef helpers) after s.Run(...) has started its subtests.
Common situations: Goroutines spawned in suite setup that later call s.Context()/s.Awaitf() after Run() started; deferred code calling s.T() during teardown; code written before a suite was converted to parallelsuite.
Related errors
- parallelsuite: assertion called on %q after Run() was called
- missing RespondWorkflowTaskCompletedRequest return
- history is nil
- history events are empty
- missing PollWorkflowTaskQueueResponse
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/f4ff7c95253c7489.
Report an issue: GitHub.