hashicorp/terraform · error

failed to create project

Error message

failed to create project %s: %v

What it means

Thrown by the Cloud backend when auto-creating a TFE/HCP project named in the `cloud { project = ... }` block. The backend first attempted a lookup that returned nothing, then called Projects.Create; any failure other than tfe.ErrResourceNotFound is surfaced here. ErrResourceNotFound from Create is intentionally swallowed (it signals the projects feature is absent), but every other API failure (auth, name conflict, validation, transport) propagates.

Solutions

  1. Pre-create the project in the TFE/HCP UI (or via API) and keep the cloud block referencing its name so Create is never attempted.
  2. Grant the service token organization-level 'Manage Projects' (or admin) permission so Projects.Create succeeds.
  3. Sanitize the project name to [A-Za-z0-9_-] and stay within length limits before running init.
  4. For concurrent pipelines racing on a new project, gate project creation behind a single job or use an external provisioner.

Example fix

// before
cloud {
  organization = "acme"
  project      = "Team A Workspace!"
  workspaces { name = "prod" }
}

// after
cloud {
  organization = "acme"
  project      = "team-a"
  workspaces { name = "prod" }
}
Defensive patterns

Strategy: validation

Validate before calling

// before init, preflight project creation prerequisites
func canCreateProject(client *tfe.Client, org, project string) error {
    if !regexp.MustCompile(`^[A-Za-z0-9_-]+$`).MatchString(project) {
        return fmt.Errorf("project name %q has invalid characters", project)
    }
    // verify org is reachable and token has admin scope
    if _, err := client.Organizations.Read(ctx, org); err != nil {
        return fmt.Errorf("cannot read org %s: %w", org, err)
    }
    // if project already exists, Create won't be attempted
    if p, err := client.Projects.Read(ctx, org, project); err == nil {
        _ = p // exists, safe
    } else if err != tfe.ErrResourceNotFound {
        return err
    }
    return nil
}

Prevention

When it happens

Trigger: b.client.Projects.Create(ctx, b.Organization, createOpts) returns err != nil AND err != tfe.ErrResourceNotFound. Concretely: 401/403 when the token lacks org-level project-management scope; 409 if a project with that name appears between the lookup and the create (race); 422 for names with illegal characters; 5xx or network/timeout from the TFE/TFE-instance host.

Common situations: A user adds `project = "team-a"` to a cloud block expecting auto-creation, but the API token only has workspace-level permissions. Or two developers running `terraform init` simultaneously against a fresh project name. Or a project name containing spaces/slashes that the API rejects.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/11b927aa90dfc86c. Report an issue: GitHub.

Appendix: source

Thrown at internal/cloud/backend.go:799

		if b.WorkspaceMapping.Strategy() == WorkspaceTagsStrategy {
			workspaceCreateOptions.Tags = b.WorkspaceMapping.tfeTags()
		} else if b.WorkspaceMapping.Strategy() == WorkspaceKVTagsStrategy {
			workspaceCreateOptions.TagBindings = b.WorkspaceMapping.asTFETagBindings()
		}

		// Create project if not exists, otherwise use it
		if workspaceCreateOptions.Project == nil && b.WorkspaceMapping.Project != "" {
			// If we didn't find the project, try to create it
			if workspaceCreateOptions.Project == nil {
				createOpts := tfe.ProjectCreateOptions{
					Name: b.WorkspaceMapping.Project,
				}
				// didn't find project, create it instead
				log.Printf("[TRACE] cloud: Creating %s project %s/%s", b.appName, b.Organization, b.WorkspaceMapping.Project)
				project, err := b.client.Projects.Create(context.Background(), b.Organization, createOpts)
				if err != nil && err != tfe.ErrResourceNotFound {
					return nil, diags.Append(fmt.Errorf("failed to create project %s: %v", b.WorkspaceMapping.Project, err))
				}
				configuredProject = project
				workspaceCreateOptions.Project = configuredProject
			}
		}

		// Create a workspace
		log.Printf("[TRACE] cloud: Creating %s workspace %s/%s", b.appName, b.Organization, name)
		workspace, err = b.client.Workspaces.Create(context.Background(), b.Organization, workspaceCreateOptions)
		if err != nil {
			return nil, diags.Append(fmt.Errorf("error creating workspace %s: %v", name, err))
		}

		remoteTFVersion = workspace.TerraformVersion

		// Attempt to set the new workspace to use this version of Terraform. This
		// can fail if there's no enabled tool_version whose name matches our
		// version string, but that's expected sometimes -- just warn and continue.

View on GitHub (pinned to d32a084675)