diff --git a/command/format/diff.go b/command/format/diff.go index e80c7c637..260c031de 100644 --- a/command/format/diff.go +++ b/command/format/diff.go @@ -856,6 +856,10 @@ func ctyGetAttrMaybeNull(val cty.Value, name string) cty.Value { } func ctyCollectionValues(val cty.Value) []cty.Value { + if !val.IsKnown() { + return nil + } + ret := make([]cty.Value, 0, val.LengthInt()) for it := val.ElementIterator(); it.Next(); { _, value := it.Element() diff --git a/plans/objchange/compatible.go b/plans/objchange/compatible.go index 9298dc48e..83b717554 100644 --- a/plans/objchange/compatible.go +++ b/plans/objchange/compatible.go @@ -64,7 +64,7 @@ func assertObjectCompatible(schema *configschema.Block, planned, actual cty.Valu return errs } case configschema.NestingList, configschema.NestingMap, configschema.NestingSet: - if plannedV.LengthInt() == 1 { + if plannedV.IsKnown() && plannedV.LengthInt() == 1 { elemVs := plannedV.AsValueSlice() if allLeafValuesUnknown(elemVs[0]) { return errs @@ -84,6 +84,10 @@ func assertObjectCompatible(schema *configschema.Block, planned, actual cty.Valu // whether there are dynamically-typed attributes inside. However, // both support a similar-enough API that we can treat them the // same for our purposes here. + if !plannedV.IsKnown() { + continue + } + plannedL := plannedV.LengthInt() actualL := actualV.LengthInt() if plannedL != actualL { @@ -125,6 +129,9 @@ func assertObjectCompatible(schema *configschema.Block, planned, actual cty.Valu } } } else { + if !plannedV.IsKnown() { + continue + } plannedL := plannedV.LengthInt() actualL := actualV.LengthInt() if plannedL != actualL { @@ -146,6 +153,9 @@ func assertObjectCompatible(schema *configschema.Block, planned, actual cty.Valu // content is also their key, and so we have no way to correlate // them. Because of this, we simply verify that we still have the // same number of elements. + if !plannedV.IsKnown() { + continue + } plannedL := plannedV.LengthInt() actualL := actualV.LengthInt() if plannedL < actualL { @@ -241,10 +251,12 @@ func assertValueCompatible(planned, actual cty.Value, path cty.Path) []error { // so we can't correlate them properly. However, we will at least check // to ensure that the number of elements is consistent, along with // the general type-match checks we ran earlier in this function. - plannedL := planned.LengthInt() - actualL := actual.LengthInt() - if plannedL < actualL { - errs = append(errs, path.NewErrorf("length changed from %d to %d", plannedL, actualL)) + if planned.IsKnown() { + plannedL := planned.LengthInt() + actualL := actual.LengthInt() + if plannedL < actualL { + errs = append(errs, path.NewErrorf("length changed from %d to %d", plannedL, actualL)) + } } } diff --git a/terraform/resource.go b/terraform/resource.go index d1941739b..9db0f2ab4 100644 --- a/terraform/resource.go +++ b/terraform/resource.go @@ -276,6 +276,10 @@ func newResourceConfigShimmedComputedKeys(obj cty.Value, schema *configschema.Bl } blockVal := obj.GetAttr(typeName) + if !blockVal.IsKnown() { + continue + } + switch blockS.Nesting { case configschema.NestingSingle: keys := newResourceConfigShimmedComputedKeys(blockVal, &blockS.Block, fmt.Sprintf("%s%s.", prefix, typeName))