Skip to content

Commit ceafcf1

Browse files
committed
RPC: Fix getObject() using wrong baseline for receiving diffs
getObject() used localObjects as the diff baseline when receiving from the remote peer. But the remote computes diffs against the last synced state (remoteObjects), not the local state. When the local side modifies a tree (e.g., via a local recipe) before calling getObject(), the two baselines diverge, producing a hybrid tree that corrupts remoteObjects and causes subsequent transfers to fail with IndexError/desync. Fix: use remoteObjects (the last synced state) as the baseline, matching what the remote peer uses. Python's get_object_from_java() already did this correctly; Java and TypeScript had the same bug.
1 parent 886de26 commit ceafcf1

2 files changed

Lines changed: 12 additions & 5 deletions

File tree

rewrite-core/src/main/java/org/openrewrite/rpc/RewriteRpc.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -461,16 +461,19 @@ List<String> getCursorIds(@Nullable Cursor cursor) {
461461

462462
@VisibleForTesting
463463
public <T> T getObject(String id, @Nullable String sourceFileType) {
464-
// Check if we have a cached version of this object
465-
Object localObject = localObjects.get(id);
464+
// Use the last synced state as the baseline for receiving diffs.
465+
// This must match what the remote used as its baseline when computing the diff.
466+
// Using localObjects here would be wrong if Java modified the tree locally
467+
// (e.g., via a Java-side recipe) since the remote doesn't know about those changes.
468+
Object before = remoteObjects.get(id);
466469

467470
RpcReceiveQueue q = new RpcReceiveQueue(
468471
remoteRefs,
469472
() -> send("GetObject", new GetObject(id, sourceFileType), GetObjectResponse.class),
470473
sourceFileType,
471474
log.get()
472475
);
473-
Object remoteObject = q.receive(localObject, null);
476+
Object remoteObject = q.receive(before, null);
474477
if (q.take().getState() != END_OF_OBJECT) {
475478
throw new IllegalStateException("Expected END_OF_OBJECT");
476479
}

rewrite-javascript/rewrite/src/rpc/rewrite-rpc.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,11 @@ export class RewriteRpc {
124124
}
125125

126126
async getObject<P>(id: string, sourceFileType?: string): Promise<P> {
127-
const localObject = this.localObjects.get(id);
127+
// Use the last synced state as the baseline for receiving diffs.
128+
// This must match what the remote used as its baseline when computing the diff.
129+
// Using localObjects here would be wrong if the local side modified the tree
130+
// (e.g., via a local recipe) since the remote doesn't know about those changes.
131+
const before = this.remoteObjects.get(id);
128132

129133
const q = new RpcReceiveQueue(this.remoteRefs, sourceFileType, () => {
130134
return this.connection.sendRequest(
@@ -133,7 +137,7 @@ export class RewriteRpc {
133137
);
134138
}, this.logger, this.traceGetObject.receive);
135139

136-
const remoteObject = await q.receive<P>(localObject);
140+
const remoteObject = await q.receive<P>(before as P);
137141

138142
const eof = (await q.take());
139143
if (eof.state !== RpcObjectState.END_OF_OBJECT) {

0 commit comments

Comments
 (0)