Repository: opentofu/opentofu
File: internal/tofu/context_apply.go (Go)

Code before:
		diags = diags.Append(tfdiags.Sourceless(
			tfdiags.Error,
			"Cannot apply failed plan",
			`The given plan is incomplete due to errors during planning, and so it cannot be applied.`,
		))
		return nil, diags
	}

	for _, rc := range plan.Changes.Resources {
		// Import is a no-op change during an apply (all the real action happens during the plan) but we'd
		// like to show some helpful output that mirrors the way we show other changes.
		if rc.Importing != nil {
			for _, h := range c.hooks {
				// In the future, we may need to call PostApplyImport separately elsewhere in the apply
				// operation. For now, though, we'll call Pre and Post hooks together.
				_, err := h.PreApplyImport(rc.Addr, *rc.Importing)
				if err != nil {
					panic(err)
				}
				_, err = h.PostApplyImport(rc.Addr, *rc.Importing)
				if err != nil {
					panic(err)
				}

			}
		}

		// Following the same logic, we want to show helpful output for forget operations as well.
		if rc.Action == plans.Forget {
			for _, h := range c.hooks {
				_, err := h.PreApplyForget(rc.Addr)
				if err != nil {
					panic(err)
				}
				_, err = h.PostApplyForget(rc.Addr)
				if err != nil {
					panic(err)
				}
			}
		}
	}

	graph, operation, diags := c.applyGraph(plan, config, true)
	if diags.HasErrors() {
		return nil, diags
	}

	workingState := plan.PriorState.DeepCopy()
	walker, walkDiags := c.walk(graph, operation, &graphWalkOpts{
		Config:     config,
		InputState: workingState,

Review comment (suggestion):
Hmm, I wonder why these errors were not caught in the first place? It feels like an oversight but there may have been a reason that it didn't result in a panic before.

Code after:

	if plan.Errored {
		diags = diags.Append(tfdiags.Sourceless(
			tfdiags.Error,
			"Cannot apply failed plan",
			`The given plan is incomplete due to errors during planning, and so it cannot be applied.`,
		))
		return nil, diags
	}

	for _, rc := range plan.Changes.Resources {
		// Import is a no-op change during an apply (all the real action happens during the plan) but we'd
		// like to show some helpful output that mirrors the way we show other changes.
		if rc.Importing != nil {
			for _, h := range c.hooks {
				// In the future, we may need to call PostApplyImport separately elsewhere in the apply
				// operation. For now, though, we'll call Pre and Post hooks together.
				_, err := h.PreApplyImport(rc.Addr, *rc.Importing)
				if err != nil {
					return nil, diags.Append(err)
				}
				_, err = h.PostApplyImport(rc.Addr, *rc.Importing)
				if err != nil {
					return nil, diags.Append(err)
				}
			}
		}

		// Following the same logic, we want to show helpful output for forget operations as well.
		if rc.Action == plans.Forget {
			for _, h := range c.hooks {
				_, err := h.PreApplyForget(rc.Addr)
				if err != nil {
					return nil, diags.Append(err)
				}
				_, err = h.PostApplyForget(rc.Addr)
				if err != nil {
					return nil, diags.Append(err)
				}
			}
		}
	}

	providerFunctionTracker := make(ProviderFunctionMapping)

	graph, operation, diags := c.applyGraph(plan, config, providerFunctionTracker)
	if diags.HasErrors() {
		return nil, diags
	}

	workingState := plan.PriorState.DeepCopy()