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
- Read the wrapped inner message to identify the exact broken reference in environments[i]
- Add the missing referenced entry (inventory/key/view/template) to the backup file
- Fix the environment's reference to match an existing name in the corresponding section
- 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
- Run Verify() immediately after generating or editing a backup
- Fix the inner (wrapped) error, not just the index prefix
- Keep all sections referenced by environments complete in the backup
- Validate merged backup files for cross-references
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)