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

  1. Correct the attribute name/path to an existing ConfigType field
  2. Inspect util.ConfigType (or the config reference docs) for the exact field name
  3. Use util.ConfigValidate / grep the struct to confirm the path exists before setting
  4. 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

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


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)