bytebase/bytebase · error

plan %d not found

Error message

plan %d not found

What it means

Thrown when GetPlan returns (nil, nil): the plan associated with the task no longer exists. Drift validation requires the plan to compare the task's SQL against the planned schema, so the task run is refused with this message naming the plan ID.

Source

Thrown at backend/runner/taskrun/running_scheduler.go:303

	}

	database, err := s.store.GetDatabase(ctx, &store.FindDatabaseMessage{
		InstanceID:   &task.InstanceID,
		DatabaseName: task.DatabaseName,
	})
	if err != nil {
		return errors.Wrapf(err, "failed to get database for drift validation")
	}
	if database == nil {
		return errors.Errorf("target database %q on instance %q has been deleted", task.GetDatabaseName(), task.InstanceID)
	}

	plan, err := s.store.GetPlan(ctx, &store.FindPlanMessage{ProjectID: task.ProjectID, UID: &task.PlanID})
	if err != nil {
		return errors.Wrapf(err, "failed to get plan for drift validation")
	}
	if plan == nil {
		return errors.Errorf("plan %d not found", task.PlanID)
	}

	return checkTaskDrift(task, database, plan)
}

// checkTaskDrift performs the actual drift comparison logic.
// Returns nil if no drift, or an error describing the drift.
func checkTaskDrift(task *store.TaskMessage, database *store.DatabaseMessage, plan *store.PlanMessage) error {
	// Check project drift.
	if database.ProjectID != plan.ProjectID {
		return errors.Errorf("target database belongs to project %q, but plan belongs to project %q", database.ProjectID, plan.ProjectID)
	}

	// Check environment drift.
	if task.Environment != "" && database.EffectiveEnvironmentID != nil && *database.EffectiveEnvironmentID != task.Environment {
		return errors.Errorf("target database is in environment %q, but task expected environment %q", *database.EffectiveEnvironmentID, task.Environment)
	}

View on GitHub (pinned to 1870550677)

Solutions

  1. Cancel the orphan task and create a fresh plan/task pair
  2. Restore the plan if deletion was accidental
  3. Check task.PlanID against existing plans in the project
  4. Prevent deleting plans that have pending task runs
Defensive patterns

Strategy: validation

Validate before calling

plan, err := store.GetPlan(ctx, &store.FindPlanMessage{ProjectID: task.ProjectID, UID: &task.PlanID})
if err != nil { return err }
if plan == nil { return fmt.Errorf("plan %d missing", task.PlanID) }

Type guard

func planPresent(plan *store.PlanMessage) bool { return plan != nil }

Try / catch

if err := s.validateTaskFreshness(ctx, task); err != nil {
	if strings.Contains(err.Error(), "plan ") && strings.Contains(err.Error(), "not found") {
		return failTaskRun(task, "orphan task: plan removed")
	}
	return err
}

Prevention

When it happens

Trigger: Plan deleted (directly or via project/pipeline cleanup) after the task was created but before its run started; validateTaskFreshness sees plan == nil.

Common situations: Plan removed during pipeline re-planning while an old task was still queued; data cleanup purging old plans; import/migration of projects leaving orphan tasks.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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