weaviate/weaviate · error

export ID cannot be empty

Error message

export ID cannot be empty

What it means

Participant.Commit refuses to proceed when the exportID argument is an empty string. Commit must identify a previously prepared export reservation; an empty ID can never match one, so the call is rejected up front before any locks, backend I/O, or snapshot waits. It is a fail-fast input validation guard, not a state problem.

Source

Thrown at usecases/export/participant.go:236

		return nil
	}
	if err := f(); err != nil {
		return err
	}

	p.logger.WithField("action", "export_participant").
		WithField("export_id", req.ID).
		WithField("node", req.NodeName).
		Info("participant prepared for export")

	return nil
}

// Commit starts the actual export. Must be called after a successful Prepare.
func (p *Participant) Commit(ctx context.Context, exportID string) error {
	if exportID == "" {
		return fmt.Errorf("export ID cannot be empty")
	}

	// Peek at the prepared request and pending snapshot under a short lock.
	// Fail early if no matching export is prepared — no point doing backend
	// I/O or waiting for snapshots.
	p.mu.Lock()
	req := p.preparedReq
	pending := p.pending
	if req == nil || req.ID != exportID || pending == nil {
		p.clearAndRelease()
		p.mu.Unlock()
		return fmt.Errorf("no matching export prepared for ID %q", exportID)
	}
	p.mu.Unlock()

	// Initialize the backend outside the lock — this may involve network
	// I/O (S3 bucket verification, directory creation) and must not block
	// Abort/IsRunning callers. If initialization fails, backendStore stays

View on GitHub (pinned to 75aa4b6d11)

Solutions

  1. Ensure the export ID is generated/set before calling Commit (e.g. a UUID from the coordinator's Prepare call).
  2. Validate the ID at the coordinator/API layer so an empty value never reaches Participant.Commit.
  3. If the ID comes from a request payload, add required-field validation on deserialization and reject it early.

Example fix

// before
var exportID string
err := participant.Commit(ctx, exportID) // "export ID cannot be empty"
// after
exportID := prepareResp.ID
if exportID == "" {
    return fmt.Errorf("coordinator returned empty export ID")
}
err := participant.Commit(ctx, exportID)
Defensive patterns

Strategy: validation

Validate before calling

if exportID == "" {
    return fmt.Errorf("refusing to commit: export ID is empty")
}
err := participant.Commit(ctx, exportID)

Type guard

func hasExportID(id string) bool { return strings.TrimSpace(id) != "" }

Try / catch

if err := participant.Commit(ctx, exportID); err != nil {
    if strings.Contains(err.Error(), "export ID cannot be empty") {
        return fmt.Errorf("caller bug: empty export ID passed to Commit")
    }
    return err
}

Prevention

When it happens

Trigger: Calling p.Commit(ctx, "") directly; a caller propagating an unset/zero-value export ID variable; a coordinator bug where the ID field was never assigned before calling Commit.

Common situations: Happens when code constructs the export request struct without setting ID, or when a test/driver passes a literal empty string, or when an ID is lost crossing an API boundary (e.g. unmarshaled protobuf/JSON with a missing field).

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 weaviate/weaviate@75aa4b6d11 (2026-09-04). Data as JSON: /api/errors/9db35a1e930adb60. Report an issue: GitHub.