unknwon/the-way-to-go_ZH_CN · error
key not found
Error message
key not found
What it means
Returned by URLStore.Get in the chapter 19 URL-shortener after the RPC-style refactor: Get(key, url *string) takes a read lock (s.mu.RLock with defer RUnlock), and when the map lookup s.urls[*key] misses it returns errors.New("key not found"). The Redirect HTTP handler prints the error's string form — effectively the 404 cause for an unknown short key.
Source
Thrown at eBook/19.8.md:40
```
要使 `URLStore` 成为 RPC 服务,需要修改 `Put()` 和 `Get()` 方法使它们符合上述函数签名。以下是修改后的签名:
```go
func (s *URLStore) Get(key, url *string) error
func (s *URLStore) Put(url, key *string) error
```
`Get()` 代码变更为:
```go
func (s *URLStore) Get(key, url *string) error {
s.mu.RLock()
defer s.mu.RUnlock()
if u, ok := s.urls[*key]; ok {
*url = u
return nil
}
return errors.New("key not found")
}
```
现在,键和长 URL 都变成了指针,必须加上前缀 `*` 来取得它们的值,例如 `*key` 这种形式。`u` 是一个值,可以用 `*url = u` 来将其赋值给指针。
接着对 `Put()` 代码做同样的改动:
```go
func (s *URLStore) Put(url, key *string) error {
for {
*key = genKey(s.Count())
if err := s.Set(key, url); err == nil {
break
}
}
if s.save != nil {
s.save <- record{*key, *url}
}
return nilView on GitHub (pinned to 7a54d34d36)
Solutions
- On startup, always run load() to replay the persisted store before serving traffic, so previously issued keys stop missing
- In Redirect, treat this error as 404: if err := store.Get(&key, &url); err != nil { http.NotFound(w, req); return } — or redirect to the homepage per the book's variant
- Promote the string to a sentinel (var ErrKeyNotFound = errors.New("key not found")) and branch with errors.Is so refactors keep the 404 mapping working
- If keys vanish under load, verify Get's RLock/RUnlock pairing and that Put still writes records through save <- record{*key, *url}
Example fix
// before
err := store.Get(&key, &url)
if err != nil {
fmt.Println("Error:", err) // raw 'key not found' leaked to stdout
}
// after
var url string
if err := store.Get(&key, &url); err != nil {
http.Error(w, "no such key: "+key, http.StatusNotFound)
return
}
http.Redirect(w, req, url, http.StatusFound) Defensive patterns
Strategy: fallback
Try / catch
var url string
if err := store.Get(&key, &url); err != nil {
// unknown short key: degrade gracefully
http.NotFound(w, req) // or redirect to the homepage
return
}
http.Redirect(w, req, url, http.StatusFound) Prevention
- Replay persisted records via load() before the server starts listening, so issued keys survive restarts
- Treat 'key not found' as an expected branch: map it to 404 or a homepage redirect, never a 500
- Promote the message to an exported sentinel (ErrKeyNotFound) and match with errors.Is so refactors keep the mapping
- Monitor the miss rate: a spike usually means persistence or replication broke, not user typos
When it happens
Trigger: The Redirect handler receives /somekey that was never Put: the key is absent from s.urls. Also key-format mismatches (keys come from genKey(s.Count()) and are short strings), keys lost because the service restarted without load() replaying the persisted store, or typo'd/garbled short URLs.
Common situations: Persistence bugs: the save channel dropped records, data_store.txt was not loaded on startup, or Count() desynchronized after load causing genKey to emit colliding keys; hand-typed keys with case errors; multi-instance deployments where only one replica holds the key.
Related errors
AI-assisted analysis of unknwon/the-way-to-go_ZH_CN@7a54d34d36 (2026-08-15).
Data as JSON: /api/errors/0fb86f7ddaeec2f6.
Report an issue: GitHub.