{"record":{"id":"7e505e438799a384","repo":"apache/beam","slug":"unexpected-resolveartifactresponse-to-getartifact-v","errorCode":null,"errorMessage":"unexpected ResolveArtifactResponse to GetArtifact: %v","messagePattern":"unexpected ResolveArtifactResponse to GetArtifact: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/runners/prism/internal/jobservices/artifact.go","lineNumber":81,"sourceCode":"\t\t\t\t}\n\t\t\t\tif in.GetIsLast() {\n\t\t\t\t\tslog.Debug(\"GetArtifact finished\",\n\t\t\t\t\t\tslog.Group(\"dep\",\n\t\t\t\t\t\t\tslog.String(\"urn\", dep.GetTypeUrn()),\n\t\t\t\t\t\t\tslog.String(\"payload\", string(dep.GetTypePayload()))),\n\t\t\t\t\t\tslog.Int(\"bytesReceived\", buf.Len()),\n\t\t\t\t\t\tslog.String(\"rtype\", fmt.Sprintf(\"%T\", in.GetResponse())),\n\t\t\t\t\t)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\t// Here's where we go through each environment's artifacts.\n\t\t\t\t// We do nothing with them.\n\t\t\t\tswitch req := in.GetResponse().(type) {\n\t\t\t\tcase *jobpb.ArtifactResponseWrapper_GetArtifactResponse:\n\t\t\t\t\tbuf.Write(req.GetArtifactResponse.GetData())\n\n\t\t\t\tcase *jobpb.ArtifactResponseWrapper_ResolveArtifactResponse:\n\t\t\t\t\terr := fmt.Errorf(\"unexpected ResolveArtifactResponse to GetArtifact: %v\", in.GetResponse())\n\t\t\t\t\tslog.Error(\"GetArtifact failure\", slog.Any(\"error\", err))\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(s.artifacts) == 0 {\n\t\t\t\ts.artifacts = map[string][]byte{}\n\t\t\t}\n\t\t\ts.artifacts[string(dep.GetTypePayload())] = buf.Bytes()\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (s *Server) ResolveArtifacts(_ context.Context, req *jobpb.ResolveArtifactsRequest) (*jobpb.ResolveArtifactsResponse, error) {\n\treturn &jobpb.ResolveArtifactsResponse{\n\t\tReplacements: req.GetArtifacts(),\n\t}, nil\n}","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/runners/prism/internal/jobservices/artifact.go#L63-L99","documentation":"In the prism job server's reverse artifact retrieval service, GetArtifact requests are answered with a stream of ArtifactResponseWrapper messages. The code expects the wrapper for a GetArtifact call to carry GetArtifactResponse data chunks. If the SDK harness instead replies with a ResolveArtifactResponse (the answer to the other RPC type), the server logs and returns this error — the response type does not match the outstanding request.","triggerScenarios":"A worker returning an ArtifactResponseWrapper_ResolveArtifactResponse in the stream opened by a GetArtifact request handled by ReverseArtifactRetrievalService.","commonSituations":"SDK harness/job-server protocol version skew (client answering the wrong RPC); buggy or custom artifact plugins on the worker side.","solutions":["Align the SDK harness and prism job server versions so artifact RPC responses match request types.","Check the worker's artifact retrieval implementation — it must answer GetArtifact requests with GetArtifactResponse chunks.","Capture job logs to see which artifact triggered the mismatch and reproduce with that artifact's staging."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Client-side: ensure GetArtifact is answered with GetArtifactResponse wrappers\nif _, ok := wrapper.Response.(*jobpb.ArtifactResponseWrapper_GetArtifactResponse); !ok {\n    return fmt.Errorf(\"wrong response type for GetArtifact: %T\", wrapper.Response)\n}","typeGuard":"// Go type guard on the streamed response\nfunc isGetArtifactResponse(w *jobpb.ArtifactResponseWrapper) bool {\n    _, ok := w.GetResponse().(*jobpb.ArtifactResponseWrapper_GetArtifactResponse)\n    return ok\n}","tryCatchPattern":"err := streamArtifact(ctx, req)\nif err != nil && strings.Contains(err.Error(), \"unexpected ResolveArtifactResponse\") {\n    log.Fatalf(\"worker answered the wrong artifact RPC; check harness/server version skew: %v\", err)\n}","preventionTips":["Deploy matching versions of prism and the SDK harness","Do not interleave ResolveArtifact handling into the GetArtifact stream","Test artifact retrieval after any Beam version upgrade"],"tags":["go","beam","artifacts","grpc"],"backgroundTag":"unexpected-response-shape","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"}