semaphoreui/semaphore · error

global role does not exist

Error message

global role does not exist: %s

What it means

When restoring template role permissions for a role marked IsGlobal, BackupTemplate.Restore calls store.GetGlobalRoleBySlug(role.Role). This error is thrown when that lookup fails, meaning the target instance has no global role with the given slug, so the template's global role permission cannot be recreated.

Solutions

  1. Create the missing global role with the exact slug on the destination instance before restoring
  2. Change roles[].role in the backup to a slug that exists globally on the target
  3. Remove the entry from templates[].roles if the global permission is not needed
  4. Synchronize RBAC configuration between instances (e.g. via provisioning/setup) before import

Example fix

// before (backup.json)
{"roles": [{"role": "template-admin", "isGlobal": true}]}
// after: either create global role "template-admin" on the target, or map to an existing slug
{"roles": [{"role": "admin", "isGlobal": true}]}
Defensive patterns

Strategy: validation

Validate before calling

for i, t := range backup.Templates {
    for _, r := range t.Roles {
        if r.IsGlobal {
            if _, err := store.GetGlobalRoleBySlug(r.Role); err != nil {
                return fmt.Errorf("templates[%d]: global role %q missing on target", i, r.Role)
            }
        }
    }
}

Try / catch

if err := backup.Restore(user, store, workflowStore); err != nil {
    var target string
    if _, scan := fmt.Sscanf(err.Error(), "global role does not exist: %s", &target); scan == nil {
        // provision the global role on the target, then retry
    }
    return err
}

Prevention

When it happens

Trigger: Restoring a backup created on an instance that has a global role slug (roles[].role where isGlobal=true) which does not exist on the destination instance's database.

Common situations: Migrating projects between Semaphore instances with different RBAC setups; destination instance missing custom global roles; global role renamed or deleted on the target after the backup was taken.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of semaphoreui/semaphore@1774ccb71a (2026-09-07). Data as JSON: /api/errors/194676929aef7f11. Report an issue: GitHub.

Appendix: source

Thrown at services/project/restore.go:368

			tplVault := vault.TemplateVault
			tplVault.ProjectID = b.meta.ID
			tplVault.TemplateID = newTemplate.ID
			tplVault.VaultKeyID = VaultKeyID

			_, err := b.store.CreateTemplateVault(tplVault)
			if err != nil {
				return err
			}
		}
	}

	if e.Roles != nil {
		for _, role := range e.Roles {
			if role.IsGlobal {
				r, err := b.store.GetGlobalRoleBySlug(role.Role)
				if err != nil {
					return fmt.Errorf("global role does not exist: %s", role.Role)
				}

				_, err = b.store.CreateTemplateRole(db.TemplateRolePerm{
					TemplateID:  newTemplate.ID,
					RoleSlug:    r.Slug,
					ProjectID:   b.meta.ID,
					Permissions: role.Permissions,
				})

				if err != nil {
					return err
				}

				continue
			}
			if k := findEntityByName[db.Role](&role.Role, b.roles); k == nil {
				return fmt.Errorf("roles[].role does not exist in roles[].name")
			} else {

View on GitHub (pinned to 1774ccb71a)