apache/beam · error

unexpected ResolveArtifactResponse to GetArtifact: %v

Error message

unexpected ResolveArtifactResponse to GetArtifact: %v

What it means

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.

Source

Thrown at sdks/go/pkg/beam/runners/prism/internal/jobservices/artifact.go:81

				}
				if in.GetIsLast() {
					slog.Debug("GetArtifact finished",
						slog.Group("dep",
							slog.String("urn", dep.GetTypeUrn()),
							slog.String("payload", string(dep.GetTypePayload()))),
						slog.Int("bytesReceived", buf.Len()),
						slog.String("rtype", fmt.Sprintf("%T", in.GetResponse())),
					)
					break
				}
				// Here's where we go through each environment's artifacts.
				// We do nothing with them.
				switch req := in.GetResponse().(type) {
				case *jobpb.ArtifactResponseWrapper_GetArtifactResponse:
					buf.Write(req.GetArtifactResponse.GetData())

				case *jobpb.ArtifactResponseWrapper_ResolveArtifactResponse:
					err := fmt.Errorf("unexpected ResolveArtifactResponse to GetArtifact: %v", in.GetResponse())
					slog.Error("GetArtifact failure", slog.Any("error", err))
					return err
				}
			}
			if len(s.artifacts) == 0 {
				s.artifacts = map[string][]byte{}
			}
			s.artifacts[string(dep.GetTypePayload())] = buf.Bytes()
		}
	}
	return nil
}

func (s *Server) ResolveArtifacts(_ context.Context, req *jobpb.ResolveArtifactsRequest) (*jobpb.ResolveArtifactsResponse, error) {
	return &jobpb.ResolveArtifactsResponse{
		Replacements: req.GetArtifacts(),
	}, nil
}

View on GitHub (pinned to 12126d8942)

Solutions

  1. Align the SDK harness and prism job server versions so artifact RPC responses match request types.
  2. Check the worker's artifact retrieval implementation — it must answer GetArtifact requests with GetArtifactResponse chunks.
  3. Capture job logs to see which artifact triggered the mismatch and reproduce with that artifact's staging.
Defensive patterns

Strategy: try-catch

Validate before calling

// Client-side: ensure GetArtifact is answered with GetArtifactResponse wrappers
if _, ok := wrapper.Response.(*jobpb.ArtifactResponseWrapper_GetArtifactResponse); !ok {
    return fmt.Errorf("wrong response type for GetArtifact: %T", wrapper.Response)
}

Type guard

// Go type guard on the streamed response
func isGetArtifactResponse(w *jobpb.ArtifactResponseWrapper) bool {
    _, ok := w.GetResponse().(*jobpb.ArtifactResponseWrapper_GetArtifactResponse)
    return ok
}

Try / catch

err := streamArtifact(ctx, req)
if err != nil && strings.Contains(err.Error(), "unexpected ResolveArtifactResponse") {
    log.Fatalf("worker answered the wrong artifact RPC; check harness/server version skew: %v", err)
}

Prevention

When it happens

Trigger: A worker returning an ArtifactResponseWrapper_ResolveArtifactResponse in the stream opened by a GetArtifact request handled by ReverseArtifactRetrievalService.

Common situations: SDK harness/job-server protocol version skew (client answering the wrong RPC); buggy or custom artifact plugins on the worker side.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/7e505e438799a384. Report an issue: GitHub.