{"record":{"id":"4e20827a92fda72d","repo":"apache/beam","slug":"dofn-terminated-without-fully-processing-restriction","errorCode":null,"errorMessage":"DoFn terminated without fully processing restriction","messagePattern":"DoFn terminated without fully processing restriction","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/runtime/exec/pardo.go","lineNumber":223,"sourceCode":"\t\t// We do not forward a ProcessContinuation on its own\n\t\tif val.Elm == nil {\n\t\t\treturn val.Continuation, nil\n\t\t}\n\t\treturn val.Continuation, n.Out[0].ProcessElement(n.ctx, val)\n\t}\n\n\tif mainIn.RTracker != nil && !mainIn.RTracker.IsDone() {\n\t\treturn nil, rtErrHelper(mainIn.RTracker.GetError())\n\t}\n\n\treturn nil, nil\n}\n\nfunc rtErrHelper(err error) error {\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn errors.New(\"DoFn terminated without fully processing restriction\")\n}\n\n// mustExplodeWindows returns true iif we need to call the function\n// for each window. It is needed if the function either observes the\n// window, either directly or indirectly via (windowed) side inputs or state.\nfunc mustExplodeWindows(fn *funcx.Fn, elm *FullValue, usesSideInput bool) bool {\n\tif len(elm.Windows) < 2 {\n\t\treturn false\n\t}\n\t_, explode := fn.Window()\n\t_, observesState := fn.StateProvider()\n\treturn explode || usesSideInput || observesState\n}\n\n// FinishBundle does post-bundle processing operations for the DoFn.\n// Note: This is not a \"FinalizeBundle\" operation. Data is not yet durably\n// persisted at this point.\nfunc (n *ParDo) FinishBundle(_ context.Context) error {","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/runtime/exec/pardo.go#L205-L241","documentation":"For splittable DoFns, processSingleWindow expects the DoFn to have claimed and fully processed its restriction before returning. rtErrHelper is called when ProcessElement returns a nil error but the restriction tracker reports unfinished work (TryClaim not exhausted), so Beam raises this error instead of silently treating the restriction as done.","triggerScenarios":"A splittable DoFn's ProcessElement returns without processing the entire restriction (the tracker's IsDone/TryClaim path indicates remaining work) and returns nil error; rtErrHelper converts the nil into this error.","commonSituations":"Custom SDF implementations that stop iterating early without checkpointing or returning a resumption error; restrictions sized incorrectly so the loop ends before the restriction is consumed; forgetting to call the tracker's TryClaim in the processing loop.","solutions":["Ensure ProcessElement processes the entire restriction before returning.","If early termination is intentional, checkpoint via the restriction tracker or return the appropriate resumption error instead of nil.","Verify the restriction tracker is being claimed in the element-processing loop and that restriction bounds are correct."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// In a custom SDF, verify the restriction is fully processed before returning nil\nif !rt.TryClaim(restrictionEnd) { return rt.GetError() } // propagate, never return nil with work left","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always drive element processing through the restriction tracker's TryClaim loop","Checkpoint or return a resumption error instead of returning nil with unfinished restriction","Test custom SDFs with restrictions that end mid-element and at boundaries"],"tags":["go","apache-beam","sdf","pardo","restriction-tracker"],"backgroundTag":"internal-invariant-violation","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}