semaphoreui/semaphore · critical
got non-existent config attribute
Error message
got non-existent config attribute
What it means
setConfigValue panics when the reflect.Value for the requested config attribute is invalid, i.e. the attribute path does not exist in the util.Config struct. Typically the caller looked up a path that matched no field (FieldByName returned zero Value) and passed it in.
Solutions
- Correct the attribute name/path to an existing ConfigType field
- Inspect util.ConfigType (or the config reference docs) for the exact field name
- Use util.ConfigValidate / grep the struct to confirm the path exists before setting
- Update scripts that reference renamed/removed config fields
Example fix
// before
util.ConfigSetAttribute("access_key_expir", "0")
// after
util.ConfigSetAttribute("access_key_expiration", "0") Defensive patterns
Strategy: validation
Validate before calling
func configFieldExists(name string) bool {
_, ok := reflect.TypeOf(util.ConfigType{}).FieldByName(name)
return ok
}
if !configFieldExists("access_key_expiration") { /* abort */ } Type guard
func validConfigPath(path string) bool {
v := reflect.Indirect(reflect.ValueOf(util.Config{}))
for _, seg := range strings.Split(path, ".") {
if v.Kind() != reflect.Struct { return false }
v = v.FieldByName(seg)
if !v.IsValid() { return false }
}
return true
} Try / catch
func safeGetConfig(path string) (val string, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("unknown config attribute %q: %v", path, r)
}
}()
return util.GetConfig(path), nil
} Prevention
- Copy attribute names from util/config.go or the config reference, never from memory
- Grep the struct for the field name before scripting config changes
- After upgrades, diff your config overrides against the new ConfigType fields
When it happens
Trigger: Calling a config-set API with a dotted path or attribute name that does not correspond to any field of ConfigType; typos in attribute names; referencing fields removed/renamed in a newer Semaphore version.
Common situations: Typo in an env-config key name; automation/scripts setting config values that no longer exist; migrations referencing old config fields.
Related errors
- cannot assign value of type
- got non-existent config attribute
- cannot assign value of type %T to field
- expected slice or json array string for field
- expected slice for field
AI-assisted analysis of semaphoreui/semaphore@1774ccb71a (2026-09-07).
Data as JSON: /api/errors/18d024a077035520.
Report an issue: GitHub.
Appendix: source
Thrown at util/config.go:1370
err := json.Unmarshal([]byte(value), mapValue.Interface())
if err != nil {
panic(err)
}
attribute.Set(mapValue.Elem())
default:
newValue, _ := CastValueToKind(value, kind)
convertedValue := reflect.ValueOf(newValue)
if convertedValue.Type().AssignableTo(attribute.Type()) {
attribute.Set(convertedValue)
} else if convertedValue.Type().ConvertibleTo(attribute.Type()) {
attribute.Set(convertedValue.Convert(attribute.Type()))
} else {
panic(fmt.Errorf("cannot assign value of type %s to field of type %s", convertedValue.Type(), attribute.Type()))
}
}
} else {
panic(fmt.Errorf("got non-existent config attribute"))
}
}
func getConfigValue(path string) string {
attribute := reflect.ValueOf(Config)
nested_path := strings.Split(path, ".")
for i, nested := range nested_path {
attribute = reflect.Indirect(attribute).FieldByName(nested)
lastDepth := len(nested_path) == i+1
if !lastDepth && attribute.Kind() != reflect.Struct && attribute.Kind() != reflect.Pointer ||
lastDepth && attribute.Kind() == reflect.Invalid {
panic(fmt.Errorf("got non-existent config attribute '%v'", path))
}
}
return fmt.Sprintf("%v", attribute)
}View on GitHub (pinned to 1774ccb71a)