apache/beam · error

error getting last message

Error message

error getting last message: %v

What it means

After fetching the stream, getEndSeqNo calls str.GetLastMsgForSubject(ctx, e.subject) to find the last message for the configured subject. If that request fails for a reason other than 'message not found' (which is handled by returning 1), the error is wrapped with this message and Estimate fails. It indicates the last-message lookup could not be completed against the JetStream stream.

Solutions

  1. Read the wrapped error to distinguish timeouts/cancellation from server errors
  2. Validate the subject matches the stream's subjects (`nats stream info <name>` shows subjects)
  3. Increase the context timeout passed to Estimate/getEndSeqNo if deadlines fire
  4. Retry the operation on transient network errors; confirm the connection is healthy
  5. Check NATS server logs for JetStream errors at the time of the request

Example fix

// before
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
// after
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) // generous deadline for large streams
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: ensure the subject is served by the stream
str, _ := js.Stream(ctx, streamName)
for _, subj := range str.CachedInfo().Config.Subjects {
	if subjectsMatch(subj, configuredSubject) { return nil }
}
return errors.New("subject not covered by stream; check configuration")

Try / catch

msg, err := str.GetLastMsgForSubject(ctx, e.subject)
if err != nil {
	if isMessageNotFound(err) { return 1, nil }
	if errors.Is(err, context.DeadlineExceeded) || isTransient(err) {
		// retry with backoff before failing
	}
	return -1, fmt.Errorf("error getting last message: %v", err)
}

Prevention

When it happens

Trigger: str.GetLastMsgForSubject returns a non-nil error that isMessageNotFound(err) does not classify as not-found: invalid subject in the request, context cancellation/timeout, server-side JetStream errors, or connection loss mid-request.

Common situations: Subject configured with a token mismatch or malformed wildcard so the server rejects the request; slow NATS server causing the context deadline to fire; transient network failure between worker and server; server returning an internal JetStream error.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


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

Appendix: source

Thrown at sdks/go/pkg/beam/io/natsio/end_estimator.go:61

	if err != nil {
		panic(err)
	}
	return end
}

func (e *endEstimator) getEndSeqNo(ctx context.Context) (int64, error) {
	str, err := e.js.Stream(ctx, e.stream)
	if err != nil {
		return -1, fmt.Errorf("error getting stream: %v", err)
	}

	msg, err := str.GetLastMsgForSubject(ctx, e.subject)
	if err != nil {
		if isMessageNotFound(err) {
			return 1, nil
		}

		return -1, fmt.Errorf("error getting last message: %v", err)
	}

	return int64(msg.Sequence) + 1, nil
}

func isMessageNotFound(err error) bool {
	var jsErr jetstream.JetStreamError
	if errors.As(err, &jsErr) {
		apiErr := jsErr.APIError()
		if apiErr.ErrorCode == jetstream.JSErrCodeMessageNotFound {
			return true
		}
	}

	return false
}

View on GitHub (pinned to 12126d8942)