semaphoreui/semaphore · critical
got non-existent config attribute
Error message
got non-existent config attribute '%v'
What it means
getConfigValue panics when a dotted attribute path cannot be walked on the util.Config struct: an intermediate segment is not a struct/pointer, or the final segment does not exist (Invalid kind). It is the read-side counterpart of error 202 and indicates the path string does not match the config struct layout.
Solutions
- Fix the dotted path to match the actual ConfigType field hierarchy
- Verify each intermediate segment is a struct in util.ConfigType
- Validate user-supplied config paths before passing them in
- Pin/reference documentation for the deployed Semaphore version, since field names change
Example fix
// before
val := util.GetConfig("db.conection.host")
// after
val := util.GetConfig("db.connection.host") Defensive patterns
Strategy: validation
Validate before calling
func configPathExists(path string) bool {
v := reflect.Indirect(reflect.ValueOf(util.Config{}))
parts := strings.Split(path, ".")
for i, seg := range parts {
if v.Kind() != reflect.Struct { return false }
v = v.FieldByName(seg)
if !v.IsValid() { return false }
if i < len(parts)-1 && v.Kind() != reflect.Struct && v.Kind() != reflect.Pointer { return false }
}
return true
} Type guard
func isReadableConfigValue(path string) (ok bool) {
defer func() { _ = recover() }()
util.GetConfig(path)
return true
} Try / catch
func safeGet(path string) (val string, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("bad config path %q: %v", path, r)
}
}()
return util.GetConfig(path), nil
} Prevention
- Only pass hardcoded, reviewed dotted paths to GetConfig
- Never build config paths from untrusted user input without validation
- Check intermediate segments are structs (e.g. `db`, then `connection`, then the field)
- Document the deployed version's config schema where paths are referenced
When it happens
Trigger: Calling getConfigValue/GetConfig (or a feature that reads config by path) with a mistyped path like `auth.email_verification_requiredd`, or a path whose intermediate node is a scalar (e.g. `db.user.foo`).
Common situations: Typo in config key inside code/templates; fields renamed between versions; building paths programmatically from user input.
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/70f3af3fe9b7eda9.
Report an issue: GitHub.
Appendix: source
Thrown at util/config.go:1383
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)
}
func validate(value any) error {
t := reflect.TypeOf(value)
v := reflect.ValueOf(value)
if t.Kind() == reflect.Ptr {
t = t.Elem()
v = reflect.Indirect(v)
}
for i := 0; i < t.NumField(); i++ {
fieldType := t.Field(i)
fieldValue := v.Field(i)View on GitHub (pinned to 1774ccb71a)