Skip to content

Conditions

Conditions are the typed status entries in status.conditions of a CAPTF object. Each has a type, a status (True, False or Unknown), a machine-readable reason and a human-readable message. The type says what is being tracked, the status says how it stands, and the reason says why. This page lists every type and every reason CAPTF sets. To go from a stuck object to the right fix, start with Troubleshooting conditions, which adds the likely cause of each reason.

Five kinds carry conditions: TerraformCluster, TerraformMachine, TerraformMachinePool, TerraformMachineTemplate and TerraformClusterIdentity. Below, “all three” means the first three. The per-kind pages list which types each kind sets: TerraformCluster, TerraformMachine, TerraformMachinePool and TerraformClusterIdentity.

Read conditions

Ready is the only condition Cluster API reads. Cluster API mirrors it into InfrastructureReady on the owning Cluster, Machine or MachinePool. Every other type is informational: it explains why Ready is what it is, and nothing outside CAPTF acts on it.

List every condition of an object with jsonpath:

kubectl get terraformcluster -n <namespace> <name> \
  -o jsonpath='{range .status.conditions[*]}{.type}{"\t"}{.status}{"\t"}{.reason}{"\t"}{.message}{"\n"}{end}'

kubectl describe prints the same list under Conditions:, with the events below it. To see the whole Cluster API tree, with each object’s Ready and the reason it is not ready, run clusterctl describe cluster <name>. See Observability for how conditions surface in events and metrics.

Most types follow normal polarity: True is healthy and False is a problem. Three types have negative polarity, where True is the problem or the unwanted state: Deleting, DriftDetected and DeletionBlocked. Paused is a state rather than a health reading: True means paused. A type that has no reason for Unknown is never Unknown. A type that is absent has not been set yet. In the Ready summary an absent input counts as Unknown, except Deleting.

Waiting is Unknown, not False

Waiting for a lease, for another object or for an approval sets Unknown. A wait never turns Ready False, and it never counts toward retry backoff.

Summary

Type Carried by Polarity Meaning
Ready All three, and TerraformClusterIdentity Normal Summary of the object’s other conditions. The one Cluster API reads.
DependenciesReady All three Normal The owner, cluster, exports, bootstrap data and variable sources the object waits for exist.
IdentityAllowed All three Normal The identity exists, allows the namespace and has its Secret.
CredentialsMirrored All three Normal The identity’s credentials are copied into the namespace for the Jobs.
RunnerRBACReady All three Normal The runner ServiceAccount and its RoleBinding exist.
ApplyJobSucceeded All three Normal Outcome of the newest apply or destroy, and why one waits or cannot start.
StateReadable All three Normal The Terraform state can be read.
RestoreJobSucceeded All three Normal Outcome of a state restore you requested.
OutputsValid All three Normal The module’s outputs satisfy the contract.
InfrastructureHealthy All three Normal The health the module reports.
DriftJobSucceeded All three Normal Outcome of the newest refresh or drift Job.
DriftDetected All three Negative The last drift check found differences.
DeletionBlocked TerraformCluster Negative A deleting cluster waits for its machines and pools.
EndpointAvailable TerraformCluster Normal A valid control-plane endpoint is known.
AutoscalingActive TerraformMachinePool Normal The module owns the pool’s desired count.
CapacityResolved TerraformMachineTemplate Normal Capacity and node info were read from the image’s labels.
Paused All three State The object or its Cluster is paused.
Deleting All three Negative The object is being deleted.

Ready

Carried by TerraformCluster, TerraformMachine, TerraformMachinePool and TerraformClusterIdentity. Polarity: normal.

Ready summarizes other conditions; see Ready summarization for which. True means every input is True. False means at least one input is False, and Unknown means none is False but at least one is Unknown. The message names the inputs that decide it, and the input’s own reason, such as Provisioning, appears there, not in Ready’s reason. A TerraformClusterIdentity does not summarize: it sets Ready from whether its credentials Secret exists.

Status Reason Meaning
True Ready Every input is healthy. Nothing to do.
True SecretFound Identity only: the Secret named by spec.secretRef exists.
False NotReady An input is False. Read the message, then the named condition below.
False SecretNotFound Identity only: the Secret does not exist, and objects that use the identity start no Job until it does. See the identity runbook.
Unknown ReadyUnknown No input is False, but one is Unknown: the object waits for its owner, a first apply, a lease or an approval. Usually transient.

DependenciesReady

Carried by all three. Polarity: normal.

The gates that must open before CAPTF renders inputs or starts a Job: the owner, the Cluster, the cluster’s infrastructure and exports, bootstrap data and variable sources. While a gate is closed, nothing is rendered or run. A deleting object skips the owner gates, so its destroy still runs.

Status Reason Meaning
True DependenciesReady Every gate is open.
False ClusterNotTerraform The owning Cluster’s infrastructureRef is not a TerraformCluster. Nothing is rendered or run. Point the Cluster at a TerraformCluster, or move the object to the right one.
False OwnerMismatch An ownerReference of the expected kind resolves to an object that does not reference this one back: a wrong or missing infrastructureRef, a UID mismatch, or a cluster.x-k8s.io/cluster-name label that disagrees with the owner. CAPTF treats the reference as forged or stale, so the object has no valid owner, no Job runs and nothing is written to the named owner or its Cluster. The message says which check failed.
False OwnerNotFound The owner object is gone. Delete this object if it is orphaned. See deletion order.
False VariablesInvalid A variablesFrom source has a key that is not a Terraform identifier or is reserved, or a value that is not UTF-8 or, for format json, not valid JSON. The message names the key, never the value. No Job starts until you correct the source. See module variables.
False VariablesSourceNotFound A ConfigMap or Secret named in spec.variablesFrom, not marked optional, is missing or lacks the captf.io/variables=true label. No Job starts. See module variables.
False WaitingForOwnerMachine A fresh TerraformMachine has only a non-controller control-plane ownerReference and no Machine one yet. Wait for Cluster API to set it.
False WaitingForOwnerMachinePool A TerraformMachinePool has ownerReferences but none to a MachinePool yet. Wait for Cluster API to set it.
Unknown WaitingForOwner The owner is not set yet. Wait, and check the object’s cluster.x-k8s.io/cluster-name label.
Unknown WaitingForClusterInfrastructure The TerraformCluster is not provisioned yet. Read its ApplyJobSucceeded and Ready.
Unknown WaitingForClusterExports The cluster module’s exports output is not readable. Check the TerraformCluster’s StateReadable and OutputsValid.
Unknown WaitingForBootstrapData The Machine’s or MachinePool’s bootstrap data Secret is not set or not found. The bootstrap provider creates it, not CAPTF. See control planes.

IdentityAllowed

Carried by all three. Polarity: normal.

Whether the resolved TerraformClusterIdentity exists, allows this namespace and has its credentials Secret. While it is not True, no Job starts, except that a deletion that needs no Job still finishes. See Identities and the identity runbook.

Status Reason Meaning
True IdentityAllowed The identity exists, allows the namespace and its Secret exists.
False IdentityNotFound No identity resolved: none is set on the object or the cluster defaults, or the named one does not exist. Fix.
False NamespaceNotAllowed The identity’s allowedNamespaces excludes this namespace. CAPTF revokes the mirror. Fix.
False SecretNotFound The identity allows the namespace but its credentials Secret does not exist. Fix.
Unknown IdentityCheckFailed CAPTF could not finish the check, for example because an API read failed. It usually clears by itself. Fix.

CredentialsMirrored

Carried by all three. Polarity: normal.

Whether the identity’s credentials are copied into the object’s namespace as the mirror Secret that its Jobs mount.

Status Reason Meaning
True Mirrored The mirror exists and is current.
False MirrorFailed Creating or updating the mirror failed, for example because a Secret with the mirror’s name belongs to something else. Fix.
Unknown MirrorPending No mirror exists yet, either before the first mirror or because IdentityAllowed is not True. Fix that first. Details.

RunnerRBACReady

Carried by all three. Polarity: normal. Never Unknown; until the controller first reaches it, the condition is absent and counts as Unknown in Ready.

Whether the runner ServiceAccount exists and is bound to the runner role in the object’s namespace. See RBAC.

Status Reason Meaning
True RBACReady The ServiceAccount and RoleBinding are in place.
False RBACFailed Creating the ServiceAccount or the captf-runner RoleBinding failed, for example because a RoleBinding with that name is not CAPTF’s. Fix.
False ServiceAccountNotOptedIn An override ServiceAccount lacks the captf.io/runner=true label. Label it, create it or drop the override; the controller retries every 30 seconds. Fix.

ApplyJobSucceeded

Carried by all three. Polarity: normal.

The outcome of the newest apply, plan or destroy Job, and the reason one waits or cannot start. A plan Job stands for the apply it plans. After one has completed the status is not Unknown, except while the next operation waits for a lease or an approval. A running apply keeps the last result. The three lease reasons are shared with DriftJobSucceeded and RestoreJobSucceeded. To diagnose a failure, read status.lastRun and the Job’s pod logs; see Failing Jobs.

Status Reason Meaning
True ApplySucceeded The newest apply succeeded.
True DestroySucceeded The destroy succeeded and cleanup follows.
False ApplyFailed An apply Job failed, or disappeared while it ran because it was deleted before it finished. The message names the Job and the failed step. The controller retries with backoff. After a Job vanished, an apply of the current inputs stays due until one succeeds; this message outranks an older blocked or plan-changed apply. See retries.
False DestroyFailed A destroy Job failed, or a destroy cannot be rendered because the durable inputs Secret is missing. It retries until it succeeds. If it cannot, see stuck destroy.
False DestructivePlanBlocked An apply stopped before a plan that deletes or replaces resources, and no approval names it. On a TerraformCluster, which includes a drift remediation, the captf.io/approve-destructive-plan annotation does not name the inputs hash it renders, and no apply of that hash runs until it does or the inputs change. On a TerraformMachinePool, it is an apply of a change of the cluster’s exports that stopped, and the annotation does not name its approval hash (the inputs hash without bootstrap_data). The reason stays while the change waits. The pool keeps applying everything else with the exports of its last successful apply, and the condition reports that apply, True, again once the change is approved, or the exports change or return to the applied ones. A pool that cannot fall back to those exports waits for approval as a cluster does, and the message says why. See the destructive-plan guard.
False IdentityNotAllowed No Job could be created because the identity does not allow the namespace or is gone. Allow the namespace again, or abandon a deleting object.
False ImageInvalid The runner reported an image-layout error: no /captf/module or a non-executable command. Rebuild the image to the image contract.
False ImagePullFailed The pod stayed in ErrImagePull or ImagePullBackOff past activeDeadlineSeconds. See image pull failures.
False InputsTooLarge The rendered root module and variables exceed what a Secret can carry, so no Job starts. See size limits.
False JobDeadlineExceeded The Job hit activeDeadlineSeconds. See deadlines.
False JobPolicyInvalid The effective job policy, the object’s own merged over the cluster defaults and the built-in defaults, gives a lockTimeoutSeconds that is not below activeDeadlineSeconds, so no Job starts. See the merged-policy check.
Unknown NoApplyYet No apply has completed yet. Check DependenciesReady, IdentityAllowed and the Jobs.
Unknown PlanAwaitingApproval A TerraformCluster with applyPolicy: Manual waits for approval of the plan in status.plan, through the captf.io/approve-plan annotation naming its hash. See manual approval.
Unknown PlanChanged An approved apply planned other changes than the approved plan and stopped before applying them. The new plan in status.plan waits for approval. See manual approval.
Unknown WaitingForClusterOperation A machine’s or pool’s apply or destroy waits for its TerraformCluster’s to finish.
Unknown WaitingForMachineOperations A TerraformCluster’s apply or destroy waits for the applies and destroys of its machines and pools in flight. New ones wait behind it.
Unknown WaitingForRunLease Another live Job, such as one another manager instance started, holds the object’s run lease. No Job starts until it finishes. Never delete a Lease by hand. See leases.

StateReadable

Carried by all three. Polarity: normal.

Whether CAPTF can read the object’s Terraform state from its backend Secrets. While it is False, no Job runs, and a deleting object’s deletion is held, except for StateLocked. See unreadable state and State.

Status Reason Meaning
True StateRead The state was read.
False StateCorrupt The state cannot be decoded. Restore a backup taken before the damage. Fix.
False StateEncrypted The state carries OpenTofu client-side encryption, which CAPTF does not support in v1. Fix.
False StateInconsistent The state chunks disagree and do not form one complete state. Fix.
False StateLocked Something other than the object’s own runner, such as a workstation, holds the state lock. Every Job waits lockTimeoutSeconds for it and then fails. See the stale-lock runbook.
False StateLost The state Secret of an object that applied before is missing, or carries no inputs hash for an immutable kind. An object counts as having applied if it is provisioned, marked applied, digest-pinned or backed up on its own Secrets, which survive a clusterctl move. No Job runs until you restore the state. A deleting object keeps its finalizer until you restore it with captf.io/restore-state or abandon the infrastructure with captf.io/abandon-infrastructure. Fix.
Unknown StateNotFound No state exists yet. The first apply creates it. Details.

RestoreJobSucceeded

Carried by all three. Polarity: normal. Set only once you request a restore with the captf.io/restore-state annotation. Never feeds Ready.

The outcome of the newest state restore Job. A requested serial without a backup, or a restore that waits for a lease, is reported here too. See state restore.

Status Reason Meaning
True StateRestored The restore Job pushed the backup into the backend.
False RestoreBackupNotFound The annotation names no existing backup, or is not a serial. No Job starts. Pick a serial from status.stateBackups.
False RestoreFailed The restore Job failed. CAPTF does not retry it for the same serial, in status.lastRestoredSerial. To retry, remove the annotation, wait for lastRestoredSerial to clear and set it again.
Unknown WaitingForClusterOperation A machine’s or pool’s restore waits for its TerraformCluster’s operation to finish.
Unknown WaitingForMachineOperations A TerraformCluster’s restore waits for the operations of its machines and pools in flight.
Unknown WaitingForRunLease Another live Job holds the object’s run lease. No Job starts until it finishes.

OutputsValid

Carried by all three. Polarity: normal.

Whether the module’s outputs, read from state, satisfy the contract for the object’s role and the Cluster API field markers. See the module contract.

Status Reason Meaning
True OutputsValid The outputs are valid.
True InstancesTruncated A pool’s instances output had more entries than the controller keeps, and CAPTF shortened it. The pool still provisions and nothing else about its outputs is invalid. See the MachinePool role.
False FailureDomainMismatch A machine’s failure_domain output differs from the failure domain it requested.
False OutputsInvalid An output violates the contract or a Cluster API marker. The message names it.
False OutputsMissing A required output is not declared. Check the module with tfcapi-lint.
False ProviderIDChanged provider_id changed after it was first written. It is immutable. Delete the Machine to replace the instance.
Unknown OutputsPending Required outputs are null, so the first apply has not produced them yet.

InfrastructureHealthy

Carried by all three. Polarity: normal.

The health the module reports, read from state at each refresh. After provisioning it is the input that moves Ready. See Drift and health.

Status Reason Meaning
True Healthy The health state is running and healthy.
False InstanceDegraded The module reports degraded.
False InstancePending The module reports pending. Refresh runs on a doubling schedule up to five minutes.
False InstanceStopped The module reports stopped.
False InstanceTerminated The module reports terminated, or the instance vanished. See terminated instances.
False InstanceUnhealthy The state is running but healthy is false.
False Provisioning The first apply started and the object is not provisioned yet. This starts the clock for a MachineHealthCheck.
Unknown HealthUnknown The module reports unknown, an unrecognized state or no health at all.
Unknown ProviderIDMissing provider_id turned null after provisioning, for the first time. CAPTF reports the instance terminated only if the next sample is null too.
Unknown WaitingForProvisioning Before the first apply.

To replace an unhealthy machine, see machine remediation.

DriftJobSucceeded

Carried by all three. Polarity: normal. Never feeds Ready.

The outcome of the newest refresh or drift Job. See Drift.

Status Reason Meaning
True DriftChecked The newest refresh or drift Job succeeded.
False DriftJobDeadlineExceeded The drift Job hit activeDeadlineSeconds. Raise the deadline.
False DriftJobFailed The drift Job failed. The check retries with backoff. Read the Job’s logs.
Unknown DriftJobRunning A drift Job runs.
Unknown DriftNotChecked No drift check has completed, or drift checks are disabled.
Unknown DurableInputsMissing A refresh or drift Job is due but has nothing to run against: the durable inputs Secret captf-inputs-<kindshort>-<name> is gone, and the object renders no current inputs in its place (a TerraformMachine, which is immutable, never does). No refresh or drift check runs until you restore the Secret, so InfrastructureHealthy keeps its last reading and drift goes unchecked.
Unknown WaitingForRunLease A refresh or drift Job waits for the object’s run lease, which another live Job holds.

DriftDetected

Carried by all three. Polarity: negative. Never feeds Ready.

Whether the last drift check found the infrastructure differing from the desired inputs. True is the problem. See Drift.

Status Reason Meaning
True DriftPending Remediation is pending, or a cluster re-apply failed. The message names a failed, blocked or changed remediation Job. See the remediation cap.
True DriftRemediating A remediation apply runs.
True DriftReported The drift action is Report, so CAPTF reports the drift and changes nothing. Accept it or set the action to Remediate; see Remediate drift.
False NoDrift The last check found no drift.
Unknown DriftNotChecked No drift check has completed. CAPTF sets this on the first visit.

DeletionBlocked

Carried by TerraformCluster. Polarity: negative. Never feeds Ready.

Whether a deleting TerraformCluster waits for dependents. CAPTF sets it on the first visit as False.

Status Reason Meaning
True DependentsExist TerraformMachines or TerraformMachinePools of the cluster still exist, so no destroy runs. The message names them. See the cluster waits for its machines.
False NotBlocked Nothing blocks the deletion.

EndpointAvailable

Carried by TerraformCluster. Polarity: normal. Never feeds Ready. Not set before the cluster is provisioned.

Whether a valid control-plane endpoint is known. See the cluster role.

Status Reason Meaning
True EndpointAvailable A valid endpoint exists.
False WaitingForEndpoint The cluster is provisioned, and neither the module’s control_plane_endpoint output nor Cluster.spec.controlPlaneEndpoint has a valid endpoint. Output one from the module or set it on the Cluster.

AutoscalingActive

Carried by TerraformMachinePool. Polarity: normal. Never Unknown. Never feeds Ready, and Cluster API does not mirror it to the MachinePool.

Whether the pool’s autoscaler annotations are present and valid, so the module owns the desired count. See Machine pools.

Status Reason Meaning
True ReplicasManagedByModule Both annotations are present and valid, and the controller writes the observed replicas back to MachinePool.spec.replicas.
False AutoscalingAnnotationsInvalid An annotation is present but the pair is incomplete, unparsable or has min above max. The message names the problem. The pool still applies without autoscaling.
False AutoscalingDisabled Neither annotation is set. MachinePool.spec.replicas is the only source of desired capacity.
False ReplicasManagedExternally Both annotations are valid, but the MachinePool’s cluster.x-k8s.io/replicas-managed-by annotation names another controller. CAPTF does not write the observed replicas back, so the two controllers do not fight over spec.replicas. Choose one owner.

CapacityResolved

Carried by TerraformMachineTemplate, which has no Ready condition. Polarity: normal. Never Unknown.

Whether the template’s capacity and node info were read from the module image’s labels. See Templates.

Status Reason Meaning
True CapacityNotDeclared The image carries neither label. Fine unless a ClusterClass autoscaler needs the capacity.
True CapacityResolved Both labels parsed.
False CapacityLabelInvalid A label is present but invalid. Fix the label in the image; see the image contract.
False ImageInspectFailed The registry fetch or authentication failed. Fix the image reference or the credentials. The controller also emits a Warning event.

Paused

Carried by all three. Polarity: a state, not a health reading. Never Unknown. Never feeds Ready.

Whether reconciliation is paused. A paused object does bookkeeping only and starts no Job. CAPTF sets it on the first visit.

Status Reason Meaning
True Paused The object or its Cluster is paused: spec.paused on the Cluster, or the cluster.x-k8s.io/paused annotation on the object. clusterctl move pauses on purpose. A deletion waits until you unpause; see pause stops a deletion.
False NotPaused The object is not paused.

Deleting

Carried by all three. Polarity: negative. Never Unknown.

Whether the object is being deleted. True makes Ready False. The message can say what the destroy waits for. CAPTF sets it on the first visit.

Status Reason Meaning
True Deleting The deletionTimestamp is set and no more specific reason applies. Wait for the destroy. If the object does not delete, follow my object will not delete.
False NotDeleting The deletionTimestamp is not set.

Ready summarization

Ready is built with the Cluster API SetSummaryCondition helper from the inputs below. Which inputs it uses depends on the kind and on whether status.initialization.provisioned has latched True; it latches once and stays. Deleting has negative polarity, so True there makes Ready False.

Before provisioning, all three kinds summarize the same nine inputs:

  • DependenciesReady
  • IdentityAllowed
  • CredentialsMirrored
  • RunnerRBACReady
  • ApplyJobSucceeded
  • StateReadable
  • OutputsValid
  • InfrastructureHealthy
  • Deleting

After provisioning, the inputs differ per kind:

Kind Inputs after provisioning
TerraformCluster InfrastructureHealthy, Deleting
TerraformMachine InfrastructureHealthy, Deleting
TerraformMachinePool InfrastructureHealthy, ApplyJobSucceeded, Deleting

A failed re-apply does not flip a cluster’s or machine’s Ready

After provisioning, a TerraformCluster’s Ready ignores ApplyJobSucceeded. If it did not, a failed re-apply would flip the Cluster’s InfrastructureReady and suspend every MachineHealthCheck of the cluster. A TerraformMachine is immutable and behaves the same. A TerraformMachinePool is mutable and re-applied regularly, so a failed re-apply shows in its Ready.

These types never feed Ready: Paused, DriftDetected, DriftJobSucceeded, DeletionBlocked, EndpointAvailable, RestoreJobSucceeded and AutoscalingActive. An input that has not been set yet counts as Unknown, so a new object is Ready: Unknown, never True. Only Deleting is ignored while missing. Ready’s reason is always Ready, NotReady or ReadyUnknown.

A TerraformClusterIdentity does not summarize. It sets its own Ready from whether its credentials Secret exists (SecretFound or SecretNotFound).