semaphoreui/semaphore · error

error at environments

Error message

error at environments[%d]: %s

What it means

BackupFormat.Verify() validates every entry of the backup for referential integrity, starting with environments. This error wraps any error returned by BackupEnvironment.Verify for backup.Environments[i], prefixing it with the index so the caller knows which environment entry is invalid.

Solutions

  1. Read the wrapped inner message to identify the exact broken reference in environments[i]
  2. Add the missing referenced entry (inventory/key/view/template) to the backup file
  3. Fix the environment's reference to match an existing name in the corresponding section
  4. Run Verify() on the freshly exported backup before importing to catch issues at export time

Example fix

// before
if err := backup.Verify(); err != nil {
    log.Print(err) // "error at environments[2]: vault_key does not exist in keys[].name"
}
// after: fix environments[2] in the backup so keys[] contains the referenced vault_key
{"environments": [{"name": "prod", "vault_key": "prod-key"}], "keys": [{"name": "prod-key"}]}
Defensive patterns

Strategy: try-catch

Validate before calling

if err := backup.Verify(); err != nil {
    var idx int
    if n, _ := fmt.Sscanf(err.Error(), "error at environments[%d]", &idx); n == 1 {
        log.Printf("environment entry %d is invalid, fix it before import", idx)
    }
    return err
}

Try / catch

if err := backup.Verify(); err != nil {
    if strings.HasPrefix(err.Error(), "error at environments[") {
        // parse index and inner message; repair backup.Environments[i] before Restore
        return fmt.Errorf("invalid backup: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling BackupFormat.Verify() on a backup where the environment at index i fails its own verification — typically its inventory, vaultKey, vaults[].vaultKey, view, or buildTemplate references do not exist in the corresponding backup sections, or names are duplicated.

Common situations: Programmatic backup generation that omitted referenced sections; hand-edited backup JSON with broken cross-references; backup from a different project merged in; partial backups.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at services/project/restore.go:538

	}

	workflow.Nodes = nodes
	// workflow.Edges is carried by the embedded WorkflowTemplate and references
	// nodes by the IDs preserved above; writeWorkflowGraph remaps them.

	newWorkflow, err := b.workflowStore.CreateWorkflowTemplate(workflow)
	if err != nil {
		return err
	}

	b.workflows = append(b.workflows, newWorkflow)
	return nil
}

func (backup *BackupFormat) Verify() error {
	for i, o := range backup.Environments {
		if err := o.Verify(backup); err != nil {
			return fmt.Errorf("error at environments[%d]: %s", i, err.Error())
		}
	}
	for i, o := range backup.Views {
		if err := o.Verify(backup); err != nil {
			return fmt.Errorf("error at views[%d]: %s", i, err.Error())
		}
	}
	for i, o := range backup.Schedules {
		if err := o.Verify(backup); err != nil {
			return fmt.Errorf("error at templates[%d]: %s", i, err.Error())
		}
	}
	for i, o := range backup.Keys {
		if err := o.Verify(backup); err != nil {
			return fmt.Errorf("error at keys[%d]: %s", i, err.Error())
		}
	}
	for i, o := range backup.Repositories {

View on GitHub (pinned to 1774ccb71a)