Expected Behavior
When terraform apply updates any of the four repo-creation boolean fields on github_organization_settings:
members_can_create_repositories
members_can_create_public_repositories
members_can_create_private_repositories
members_can_create_internal_repositories
…the resulting server-side state should match the Terraform config exactly, regardless of which subset of those four actually changed in the diff.
Actual Behavior
Provider silently leaves the org in a state that contradicts the Terraform config, with no warning at apply time. The next terraform plan may report no drift because state is refreshed from the (now-wrong) server values.
Real-world example (Enterprise Cloud org, 2026-05-14):
- Config:
create=true, public=false, private=true, internal=false
- State before apply:
create=false, private=false (drift from UI), public=false, internal=false (matched)
terraform apply sent a PATCH containing only the two HasChange fields (members_can_create_repositories=true, members_can_create_private_repositories=true) per resource_github_organization_settings.go L183
- Server response:
create=true, public=true, private=true, internal=true, members_allowed_repository_creation_type=all
The GitHub Org API, when receiving a PATCH that sets members_can_create_repositories=true without also specifying the granular booleans, resets the deprecated members_allowed_repository_creation_type to all, which then silently overrides the unspecified granular booleans server-side. We had to manually reconcile via gh api -X PATCH after every apply that touches these fields.
Terraform Version
Terraform v1.14.8
+ provider registry.terraform.io/integrations/github v6.11.1
Affected Resource(s)
github_organization_settings
Steps to Reproduce
- Real org with Enterprise plan and config:
resource "github_organization_settings" "this" {
billing_email = "x@example.com"
members_can_create_repositories = true
members_can_create_public_repositories = false
members_can_create_private_repositories = true
members_can_create_internal_repositories = false
}
- Have server state diverge such that some but not all of the four booleans match config (easiest: toggle "members can create repositories" off in the UI, leaving the others at their existing values).
terraform apply.
gh api orgs/<org> --jq '{members_can_create_repositories, members_can_create_public_repositories, members_can_create_private_repositories, members_can_create_internal_repositories, members_allowed_repository_creation_type}' — observe members_allowed_repository_creation_type=all and the unspecified booleans flipped to true.
Root cause
buildOrganizationSettings determines what to PATCH via d.HasChange() per field, independently. This is correct in isolation but the four repo-creation booleans are mutually entangled at the API layer through the deprecated members_allowed_repository_creation_type field. Sending a partial update for the entangled set causes the API to recompute the legacy field from the partial input, which then resets the omitted fields server-side.
The go-github type explicitly documents this entanglement:
Deprecated: Use MembersCanCreatePublicRepos, MembersCanCreatePrivateRepos, MembersCanCreateInternalRepos instead. The new fields overrides the existing MembersAllowedRepositoryCreationType during 'edit' operation and does not consider 'internal' repositories during 'get' operation
Proposed Fix
Treat the four repo-creation booleans as an atomic group in buildOrganizationSettings: if any has changed, send all four (or three on non-Enterprise plans):
anyRepoCreateChange :=
d.HasChange("members_can_create_repositories") ||
d.HasChange("members_can_create_public_repositories") ||
d.HasChange("members_can_create_private_repositories") ||
(isEnterprise && d.HasChange("members_can_create_internal_repositories"))
if anyRepoCreateChange {
settings.MembersCanCreateRepos = github.Ptr(d.Get("members_can_create_repositories").(bool))
settings.MembersCanCreatePublicRepos = github.Ptr(d.Get("members_can_create_public_repositories").(bool))
settings.MembersCanCreatePrivateRepos = github.Ptr(d.Get("members_can_create_private_repositories").(bool))
if isEnterprise {
settings.MembersCanCreateInternalRepos = github.Ptr(d.Get("members_can_create_internal_repositories").(bool))
}
}
This approach:
- Fixes the silent drift for all existing users without schema changes (no breaking change)
- Aligns with go-github's deprecation guidance (use the new fields, not the legacy one)
- Avoids exposing a deprecated field via schema (which would be the alternative)
Relation to #3388
This issue and #3388 attack the same underlying problem from different angles:
Implementing the fix here makes #3388's schema exposure optional rather than necessary, and avoids the awkwardness of a Deprecated: schema field. The two approaches are not mutually exclusive.
If maintainers prefer the fix proposed here, I'm willing to put up a PR.
Code of Conduct
Expected Behavior
When
terraform applyupdates any of the four repo-creation boolean fields ongithub_organization_settings:members_can_create_repositoriesmembers_can_create_public_repositoriesmembers_can_create_private_repositoriesmembers_can_create_internal_repositories…the resulting server-side state should match the Terraform config exactly, regardless of which subset of those four actually changed in the diff.
Actual Behavior
Provider silently leaves the org in a state that contradicts the Terraform config, with no warning at apply time. The next
terraform planmay report no drift because state is refreshed from the (now-wrong) server values.Real-world example (Enterprise Cloud org, 2026-05-14):
create=true, public=false, private=true, internal=falsecreate=false, private=false(drift from UI),public=false, internal=false(matched)terraform applysent a PATCH containing only the twoHasChangefields (members_can_create_repositories=true,members_can_create_private_repositories=true) per resource_github_organization_settings.go L183create=true, public=true, private=true, internal=true,members_allowed_repository_creation_type=allThe GitHub Org API, when receiving a PATCH that sets
members_can_create_repositories=truewithout also specifying the granular booleans, resets the deprecatedmembers_allowed_repository_creation_typetoall, which then silently overrides the unspecified granular booleans server-side. We had to manually reconcile viagh api -X PATCHafter every apply that touches these fields.Terraform Version
Affected Resource(s)
github_organization_settingsSteps to Reproduce
terraform apply.gh api orgs/<org> --jq '{members_can_create_repositories, members_can_create_public_repositories, members_can_create_private_repositories, members_can_create_internal_repositories, members_allowed_repository_creation_type}'— observemembers_allowed_repository_creation_type=alland the unspecified booleans flipped totrue.Root cause
buildOrganizationSettingsdetermines what to PATCH viad.HasChange()per field, independently. This is correct in isolation but the four repo-creation booleans are mutually entangled at the API layer through the deprecatedmembers_allowed_repository_creation_typefield. Sending a partial update for the entangled set causes the API to recompute the legacy field from the partial input, which then resets the omitted fields server-side.The go-github type explicitly documents this entanglement:
Proposed Fix
Treat the four repo-creation booleans as an atomic group in
buildOrganizationSettings: if any has changed, send all four (or three on non-Enterprise plans):This approach:
Relation to #3388
This issue and #3388 attack the same underlying problem from different angles:
Implementing the fix here makes #3388's schema exposure optional rather than necessary, and avoids the awkwardness of a
Deprecated:schema field. The two approaches are not mutually exclusive.If maintainers prefer the fix proposed here, I'm willing to put up a PR.
Code of Conduct