temporalio/temporal · error

field WorkflowId is empty

Error message

field WorkflowId is empty

What it means

errEmptyWorkflowID is a sentinel in common/archiver/util.go returned by ValidateHistoryArchiveRequest, ValidateGetRequest, and ValidateVisibilityArchivalRequest when the request's WorkflowId is empty. The workflow ID is the primary key used to locate the archived workflow's history blob.

Source

Thrown at common/archiver/util.go:14

package archiver

import (
	"errors"

	archiverspb "go.temporal.io/server/api/archiver/v1"
	"go.temporal.io/server/common/log"
	"go.temporal.io/server/common/log/tag"
)

var (
	errEmptyNamespaceID      = errors.New("field NamespaceId is empty")
	errEmptyNamespace        = errors.New("field Namespace is empty")
	errEmptyWorkflowID       = errors.New("field WorkflowId is empty")
	errEmptyRunID            = errors.New("field RunId is empty")
	errInvalidPageSize       = errors.New("field PageSize should be greater than 0")
	errEmptyWorkflowTypeName = errors.New("field WorkflowTypeName is empty")
	errEmptyStartTime        = errors.New("field StartTime is empty")
	errEmptyCloseTime        = errors.New("field CloseTime is empty")
)

// TagLoggerWithArchiveHistoryRequestAndURI tags logger with fields in the archive history request and the URI
func TagLoggerWithArchiveHistoryRequestAndURI(logger log.Logger, request *ArchiveHistoryRequest, URI string) log.Logger {
	return log.With(
		logger,
		tag.ShardID(request.ShardID),
		tag.ArchivalRequestNamespaceID(request.NamespaceID),
		tag.ArchivalRequestNamespace(request.Namespace),
		tag.ArchivalRequestWorkflowID(request.WorkflowID),
		tag.ArchivalRequestRunID(request.RunID),
		tag.ArchivalRequestBranchToken(request.BranchToken),
		tag.ArchivalRequestNextEventID(request.NextEventID),

View on GitHub (pinned to bde624efd1)

Solutions

  1. Populate WorkflowID from the source request/visibility record before calling the validate API.
  2. Fail fast with Validate* at the entry point of your archival code path to catch unset IDs early.
  3. Check the upstream producer (e.g. history archival) to ensure WorkflowId is always stamped into archived records.

Example fix

// before
req := &archiver.GetHistoryRequest{NamespaceID: nsID, RunID: rid, PageSize: 100}
err := archiver.ValidateGetRequest(req)
// after
req := &archiver.GetHistoryRequest{NamespaceID: nsID, WorkflowID: wid, RunID: rid, PageSize: 100}
err := archiver.ValidateGetRequest(req)
Defensive patterns

Strategy: validation

Validate before calling

func validateWorkflowID(wfID string) error {
    if wfID == "" {
        return errors.New("WorkflowId must be set before archival request")
    }
    return nil
}

Try / catch

if err := archiver.ValidateGetRequest(req); err != nil {
    if errors.Is(err, archiver.ErrEmptyWorkflowID) {
        return nil, status.Error(codes.InvalidArgument, "WorkflowId is required")
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling ValidateHistoryArchiveRequest / ValidateGetRequest with ArchiveHistoryRequest.WorkflowID or GetHistoryRequest.WorkflowID == "", or ValidateVisibilityArchivalRequest with VisibilityRecord.GetWorkflowId() == "".

Common situations: Reconstructing get/archive requests from partial visibility records; reading WorkflowID from a struct field vs proto getter mismatch; custom archival tooling iterating over records where some lack workflow IDs.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/88becee2bc0190a5. Report an issue: GitHub.