{"record":{"id":"50d6a74268122a73","repo":"skylot/jadx","slug":"orphaned-traverser-state-50d6a7","errorCode":null,"errorMessage":"Orphaned traverser state","messagePattern":"Orphaned traverser state","errorType":"exception","errorClass":"JadxRuntimeException","httpStatus":null,"severity":"error","filePath":"jadx-core/src/main/java/jadx/core/dex/visitors/finaly/traverser/handlers/PredecessorBlockPathTraverserHandler.java","lineNumber":33,"sourceCode":"\tprivate final ISourceBlockState sourceBlockState;\n\n\tpublic PredecessorBlockPathTraverserHandler(T initialState) {\n\t\tsuper(initialState);\n\t\tthis.sourceBlockState = initialState;\n\t}\n\n\tpublic PredecessorBlockPathTraverserHandler(AtomicReference<T> initialStateRef) {\n\t\tsuper(initialStateRef);\n\t\tthis.sourceBlockState = initialStateRef.get();\n\t}\n\n\t@Override\n\tprotected void handle() {\n\t\tTraverserState baseState = getState();\n\t\tTraverserActivePathState comparator = baseState.getComparatorState();\n\t\tAtomicReference<TraverserState> stateRef = comparator.getReferenceForState(baseState);\n\t\tif (stateRef == null) {\n\t\t\tthrow new JadxRuntimeException(\"Orphaned traverser state\");\n\t\t}\n\t\tBlockNode sourceBlock = sourceBlockState.getSourceBlock();\n\t\tAbstractBlockTraverserVisitor visitor = new PredecessorBlockTraverserVisitor(baseState);\n\t\tTraverserState nextState = visitor.visit(sourceBlock);\n\n\t\tstateRef.set(nextState);\n\t}\n}\n","sourceCodeStart":15,"sourceCodeEnd":42,"githubUrl":"https://github.com/skylot/jadx/blob/e738a26571d02919f01df40de93bc9a44dee4e18/jadx-core/src/main/java/jadx/core/dex/visitors/finaly/traverser/handlers/PredecessorBlockPathTraverserHandler.java#L15-L42","documentation":"Thrown by PredecessorBlockPathTraverserHandler.handle() when the active path's getReferenceForState(baseState) returns null. This is the same orphaned-state invariant as error 161 but in the predecessor-block traversal path: the handler walks backward from a source block, and it must be able to update the state slot that holds the current state. If the state is not the finally or candidate reference of its own comparator, the handler cannot write its result.","triggerScenarios":"A predecessor-walking handler is dispatched for a state that was already superseded by a new state set into the same AtomicReference slot, or the state's comparatorState back-pointer points to a different active path than expected.","commonSituations":"Decompiling code with backward-jumping control flow (loops, continue statements inside try-finally) where the predecessor traversal encounters a state that was already advanced or replaced by a concurrent branch.","solutions":["Report to the jadx project with the input and stack trace.","Workaround: disable the finally extraction pass.","If developing jadx, trace the state lifecycle from PredecessorBlockTraverserVisitor.visit() back through the controller to ensure the state dispatched is still the live reference held by the active path."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"AtomicReference<TraverserState> ref = comparator.getReferenceForState(baseState);\nif (ref == null) {\n    // Orphaned state; cannot update the slot\n    return;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Same orphaned-state invariant as the base handler; internal to jadx.","If developing jadx, ensure predecessor handlers receive only the current live state reference."],"tags":["jadx","decompiler","finally-traverser","state-management","reference-identity"],"backgroundTag":null,"analyzedSha":"e738a26571d02919f01df40de93bc9a44dee4e18","analyzedAt":"2026-08-14T00:10:24.238Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}