{"record":{"id":"19a470b199708ded","repo":"hashicorp/terraform","slug":"consul-lock-was-lost","errorCode":null,"errorMessage":"consul lock was lost","messagePattern":"consul lock was lost","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/consul/client.go","lineNumber":40,"sourceCode":"\t\"github.com/hashicorp/terraform/internal/states/statemgr\"\n\t\"github.com/hashicorp/terraform/internal/tfdiags\"\n)\n\nconst (\n\tlockSuffix     = \"/.lock\"\n\tlockInfoSuffix = \"/.lockinfo\"\n\n\t// The Session TTL associated with this lock.\n\tlockSessionTTL = \"15s\"\n\n\t// the delay time from when a session is lost to when the\n\t// lock is released by the server\n\tlockDelay = 5 * time.Second\n\t// interval between attempts to reacquire a lost lock\n\tlockReacquireInterval = 2 * time.Second\n)\n\nvar lostLockErr = errors.New(\"consul lock was lost\")\n\n// RemoteClient is a remote client that stores data in Consul.\ntype RemoteClient struct {\n\tClient *consulapi.Client\n\tPath   string\n\tGZip   bool\n\n\tmu sync.Mutex\n\t// lockState is true if we're using locks\n\tlockState bool\n\n\t// The index of the last state we wrote.\n\t// If this is > 0, Put will perform a CAS to ensure that the state wasn't\n\t// changed during the operation. This is important even with locks, because\n\t// if the client loses the lock for some reason, then reacquires it, we\n\t// need to make sure that the state was not modified.\n\tmodifyIndex uint64\n","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/consul/client.go#L22-L58","documentation":"NestingGroup blocks are unconditionally a single, always-present group; the MinItems/MaxItems limits do not apply and must both be left at 0. Setting either is a schema definition error.","triggerScenarios":"A NestedBlock with Nesting: NestingGroup and MinItems or MaxItems != 0. Guard at internal_validate.go:82 is `blockS.MinItems != 0 || blockS.MaxItems != 0`.","commonSituations":"Changing NestingList to NestingGroup without clearing the count fields; assuming group semantics still need a min count.","solutions":["Set both MinItems: 0 and MaxItems: 0 on the NestingGroup block.","If you need occurrence limits, use NestingList or NestingSet instead of NestingGroup."],"exampleFix":"// before\n\"features\": { Nesting: configschema.NestingGroup, MinItems: 1, MaxItems: 1 },\n// after\n\"features\": { Nesting: configschema.NestingGroup, MinItems: 0, MaxItems: 0 },","handlingStrategy":"validation","validationCode":"// NestingGroup must keep MinItems and MaxItems at 0.\nfunc validGroupCounts(nb *configschema.NestedBlock) bool {\n    return nb.Nesting != configschema.NestingGroup || (nb.MinItems == 0 && nb.MaxItems == 0)\n}","typeGuard":"func groupCountsZero(min, max int) bool { return min == 0 && max == 0 }","tryCatchPattern":null,"preventionTips":["NestingGroup is a single always-present group; counts are meaningless.","When converting from NestingList, clear MinItems/MaxItems.","Use a builder that sets defaults per nesting mode."],"tags":["schema-validation","configschema","nestinggroup","minitems","maxitems","provider-schema"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}