{"record":{"id":"0bfedd2c19f6e689","repo":"apache/beam","slug":"w-error-may-be-due-to-apache-beam-go-s-migration-from-the","errorCode":null,"errorMessage":"%w\nerror may be due to Apache Beam Go's migration from the direct runner to the prism runner. While the failure(s) should be fixed, you can continue to use the direct runner with this TestMain override: `func TestMain(m *testing.M) { ptest.MainWithDefault(m, \"direct\") }`","messagePattern":"%w\nerror may be due to Apache Beam Go's migration from the direct runner to the prism runner\\. While the failure\\(s\\) should be fixed, you can continue to use the direct runner with this TestMain override: `func TestMain\\(m \\*testing\\.M\\) (.+?)`","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"sdks/go/pkg/beam/testing/ptest/ptest.go","lineNumber":106,"sourceCode":"\treturn defaultRunnerOverride\n}\n\n// MainCalled returns true iff Main or MainRet has been called.\nfunc MainCalled() bool {\n\treturn mainCalled\n}\n\n// Run runs a pipeline for testing. The semantics of the pipeline is expected\n// to be verified through passert.\nfunc Run(p *beam.Pipeline) error {\n\tr := getRunner()\n\t_, err := beam.Run(context.Background(), r, p)\n\t// Until a few versions from now (say, v2.56),\n\t// if there's an error, and\n\t// the runner is prism, and it was the set default runner, but not a manually specificed runner via the flag\n\t// augment the error with instructions to switch back to the direct runner.\n\tif err != nil && r == \"prism\" && r == defaultRunnerOverride && r != *Runner {\n\t\terr = fmt.Errorf(\"%w\\nerror may be due to Apache Beam Go's migration from the direct runner to the prism runner.\"+\n\t\t\t\" While the failure(s) should be fixed, you can continue to use the direct runner with this TestMain override:\"+\n\t\t\t\" `func TestMain(m *testing.M) { ptest.MainWithDefault(m, \\\"direct\\\") }`\", err)\n\t}\n\treturn err\n}\n\n// RunWithMetrics runs a pipeline for testing with that returns metrics.Results\n// in the form of Pipeline Result\nfunc RunWithMetrics(p *beam.Pipeline) (beam.PipelineResult, error) {\n\treturn beam.Run(context.Background(), getRunner(), p)\n}\n\n// RunAndValidate runs a pipeline for testing and validates the result, failing\n// the test if the pipeline fails.\nfunc RunAndValidate(t *testing.T, p *beam.Pipeline) beam.PipelineResult {\n\tt.Helper()\n\tpr, err := RunWithMetrics(p)\n\tif err != nil {","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/testing/ptest/ptest.go#L88-L124","documentation":"ptest.Run wraps beam.Run for pipeline tests and augments errors when the default runner (prism, after the direct runner deprecation) fails while the user never explicitly chose the runner. The wrapped message tells the developer the failure may stem from the direct-to-prism migration and shows a TestMain override to fall back to the direct runner.","triggerScenarios":"Running a ptest-based test (ptest.Run) where the default runner is \"prism\", the runner was not manually set via the --runner flag, and beam.Run returns an error. The error is then wrapped with the migration hint.","commonSituations":"Upgrading Beam versions around the v2.5x direct-to-prism runner migration; tests that passed under the direct runner now fail under prism due to behavioral differences (ordering, watermarking, transport).","solutions":["Fix the underlying pipeline failure reported inside the wrapped error","Temporarily pin the direct runner via `func TestMain(m *testing.M) { ptest.MainWithDefault(m, \"direct\") }` in the test package","Run the test with an explicit -runner flag to bypass the default (e.g. -runner direct)","Compare pipeline behavior between direct and prism runners to identify the incompatibility"],"exampleFix":"// before (test file with default prism runner)\nfunc TestMain(m *testing.M) { ptest.Main(m) }\n// after (temporary fallback to direct runner)\nfunc TestMain(m *testing.M) { ptest.MainWithDefault(m, \"direct\") }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := ptest.Run(p); err != nil {\n    if strings.Contains(err.Error(), \"prism runner\") {\n        // migration hint present: retry with -runner direct or fix pipeline\n        t.Fatalf(\"pipeline failed (possibly prism migration): %v\", err)\n    }\n    t.Fatalf(\"pipeline failed: %v\", err)\n}","preventionTips":["Read the wrapped underlying error for the real failure cause","Pin the runner explicitly via -runner flag or MainWithDefault to avoid surprises during upgrades","Review Beam release notes when crossing the direct-to-prism migration","Keep tests runner-agnostic where possible"],"tags":["go","testing","beam","runner-migration"],"backgroundTag":"deprecated-api-usage","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}