{"record":{"id":"8bca09146c6b12ff","repo":"OpenNHP/opennhp","slug":"value-not-set","errorCode":null,"errorMessage":"value not set","messagePattern":"value not set","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nhp/etcd/etcdconn.go","lineNumber":66,"sourceCode":"\tconn.ctx = ctx\n\t_, err = conn.client.Status(conn.ctx, conn.Endpoints[0])\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (conn *EtcdConn) GetValue() ([]byte, error) {\n\tval, err := conn.client.Get(conn.ctx, conn.Key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(val.Kvs) == 0 {\n\t\treturn nil, errors.New(\"key not found\")\n\t}\n\tif len(val.Kvs[0].Value) == 0 {\n\t\treturn nil, errors.New(\"value not set\")\n\t}\n\treturn val.Kvs[0].Value, nil\n}\n\nfunc (conn *EtcdConn) SetValue(v string) error {\n\t_, err := conn.client.Put(conn.ctx, conn.Key, v)\n\treturn err\n}\n\nfunc (conn *EtcdConn) WatchValue(callbackFunc func(val []byte)) {\n\t// create etcd watcher\n\tconn.watcher = clientv3.NewWatcher(conn.client)\n\n\twatchChan := conn.watcher.Watch(context.Background(), conn.Key)\n\n\tfor {\n\t\tselect {\n\t\tcase resp := <-watchChan:","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/nhp/etcd/etcdconn.go#L48-L84","documentation":"Raised by EtcdConn.GetValue when the etcd Get for conn.Key succeeds and the key exists, but the stored value is a zero-length byte slice. It means the key is present in etcd yet was written with an empty payload (e.g. someone PUT the key with no value), so the caller cannot use it as configuration. Distinct from the 'key not found' error raised a few lines above for a missing key.","triggerScenarios":"GetValue (via loadRemoteConfig/loadRemoteBaseConfig) reads a key that was created with an empty string (etcdctl put <key> \"\"), or a writer overwrote the config with empty content.","commonSituations":"Deployment script quoting bug writing an empty value; config cleared during rotation but consumers started before it was repopulated; JSON templating rendered to an empty string.","solutions":["Write the actual config value to the key (etcdctl put <key> '<non-empty json>')","Fix the writer/template that produced the empty value","Add a pre-start check that the key's value is non-empty before starting daemons","Check deployment ordering: seed etcd before starting AC/server"],"exampleFix":"// before\netcdctl put /opennhp/server/config ''\n// after\netcdctl put /opennhp/server/config '{\"logLevel\":\"info\"}'","handlingStrategy":"validation","validationCode":"resp, _ := etcdCli.Get(ctx, key)\nif resp.Count > 0 && len(resp.Kvs[0].Value) == 0 {\n    return fmt.Errorf(\"etcd key %s exists but is empty\", key)\n}","typeGuard":null,"tryCatchPattern":"val, err := conn.GetValue()\nif err != nil {\n    if err.Error() == \"value not set\" {\n        return fmt.Errorf(\"repopulate config for key %q\", conn.Key)\n    }\n    return err\n}","preventionTips":["Make the etcd writer fail if it would put an empty string","Gate daemon startup on a non-empty config checksum","Test the deployment script's quoting so variables never expand to nothing"],"tags":["go","etcd","config"],"backgroundTag":"missing-config-value","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}