bytebase/bytebase · error

cannot create rollout for a draft issue; submit it first

Error message

cannot create rollout for a draft issue; submit it first

What it means

Rollout creation guard (errDraftIssueNotSubmitted): the plan's issue is still a draft, and rollouts can only be created for submitted issues. Failing here prevents a rollout executing a plan nobody has finalized; detected via IsDraftIssueNotSubmittedError.

Source

Thrown at backend/api/v1/rollout_service.go:47

	"github.com/bytebase/bytebase/backend/plugin/db"
	parserbase "github.com/bytebase/bytebase/backend/plugin/parser/base"
	"github.com/bytebase/bytebase/backend/store"
	"github.com/bytebase/bytebase/backend/utils"
)

// RolloutService represents a service for managing rollout.
type RolloutService struct {
	v1connect.UnimplementedRolloutServiceHandler
	store          *store.Store
	dbFactory      *dbfactory.DBFactory
	bus            *bus.Bus
	webhookManager *webhook.Manager
	iamManager     *iam.Manager
}

var (
	errStaleRolloutApproval   = errors.New("cannot create rollout because issue approval is stale")
	errDraftIssueNotSubmitted = errors.New("cannot create rollout for a draft issue; submit it first")
)

// IsStaleRolloutApprovalError reports whether rollout creation lost the approval-version race.
func IsStaleRolloutApprovalError(err error) bool {
	return errors.Is(err, errStaleRolloutApproval)
}

// IsDraftIssueNotSubmittedError reports whether rollout creation was blocked by a draft issue.
func IsDraftIssueNotSubmittedError(err error) bool {
	return errors.Is(err, errDraftIssueNotSubmitted)
}

// NewRolloutService returns a rollout service instance.
func NewRolloutService(store *store.Store, dbFactory *dbfactory.DBFactory, bus *bus.Bus, webhookManager *webhook.Manager, iamManager *iam.Manager) *RolloutService {
	return &RolloutService{
		store:          store,
		dbFactory:      dbFactory,
		bus:            bus,

View on GitHub (pinned to 1870550677)

Solutions

  1. Submit the issue first (via the issue service) and then call CreateRollout
  2. Guard callers with IsDraftIssueNotSubmittedError and prompt the user to submit
  3. Check the issue's state before attempting rollout creation

Example fix

// before
_, err := rolloutClient.CreateRollout(ctx, req)
// after
if err := issueClient.SubmitIssue(ctx, issueReq); err != nil {
	return err
}
_, err := rolloutClient.CreateRollout(ctx, req)
Defensive patterns

Strategy: try-catch

Validate before calling

if issue.GetState() == v1pb.Issue_STATE_UNSPECIFIED /* or draft marker */ {
	return errors.New("submit the issue before creating a rollout")
}

Try / catch

_, err := rolloutClient.CreateRollout(ctx, req)
if err != nil {
	if v1.IsDraftIssueNotSubmittedError(err) {
		return fmt.Errorf("submit the issue first, then retry the rollout")
	}
	return err
}

Prevention

When it happens

Trigger: Calling CreateRollout (or CreateRolloutAndPendingTasks) with a plan whose issue has not been submitted — e.g. a persisted draft issue passed directly to rollout creation.

Common situations: Automation pipelines creating issues programmatically and immediately rolling out without the submit step; UI state drift where a user triggers rollout on a draft; retries against issues that were reverted to draft.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06). Data as JSON: /api/errors/cacdb1a5a9c8ffe0. Report an issue: GitHub.