A container registry that uses the AT Protocol for manifest storage and S3 for blob storage. atcr.io
docker container atproto go
81
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix record not found error handling

+28 -30
+2 -1
pkg/appview/handlers/api.go
··· 4 4 "context" 5 5 "database/sql" 6 6 "encoding/json" 7 + "errors" 7 8 "fmt" 8 9 "log" 9 10 "net/http" ··· 123 124 err = pdsClient.DeleteRecord(r.Context(), atproto.StarCollection, rkey) 124 125 if err != nil { 125 126 // If record doesn't exist, still return success (idempotent) 126 - if err.Error() != "record not found" { 127 + if !errors.Is(err, atproto.ErrRecordNotFound) { 127 128 log.Printf("UnstarRepository: Failed to delete star record: %v", err) 128 129 http.Error(w, fmt.Sprintf("Failed to delete star: %v", err), http.StatusInternalServerError) 129 130 return
+19 -4
pkg/atproto/client.go
··· 5 5 "context" 6 6 "encoding/base64" 7 7 "encoding/json" 8 + "errors" 8 9 "fmt" 9 10 "io" 10 11 "net/http" 11 12 "strings" 12 13 13 14 "github.com/bluesky-social/indigo/atproto/client" 15 + ) 16 + 17 + // Sentinel errors 18 + var ( 19 + ErrRecordNotFound = errors.New("record not found") 14 20 ) 15 21 16 22 // Client wraps ATProto operations for the registry ··· 118 124 var result Record 119 125 err := c.indigoClient.Get(ctx, "com.atproto.repo.getRecord", params, &result) 120 126 if err != nil { 121 - if strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "not found") { 122 - return nil, fmt.Errorf("record not found") 127 + // Check for RecordNotFound error from indigo's APIError type 128 + var apiErr *client.APIError 129 + if errors.As(err, &apiErr) { 130 + if apiErr.StatusCode == 404 || apiErr.Name == "RecordNotFound" { 131 + return nil, ErrRecordNotFound 132 + } 123 133 } 124 134 return nil, fmt.Errorf("getRecord failed: %w", err) 125 135 } ··· 148 158 defer resp.Body.Close() 149 159 150 160 if resp.StatusCode == http.StatusNotFound { 151 - return nil, fmt.Errorf("record not found") 161 + return nil, ErrRecordNotFound 152 162 } 153 163 154 164 if resp.StatusCode != http.StatusOK { 155 165 bodyBytes, _ := io.ReadAll(resp.Body) 156 - return nil, fmt.Errorf("get record failed with status %d: %s", resp.StatusCode, string(bodyBytes)) 166 + bodyStr := string(bodyBytes) 167 + // Check for RecordNotFound error (PDS returns 400 with this error) 168 + if strings.Contains(bodyStr, "RecordNotFound") { 169 + return nil, ErrRecordNotFound 170 + } 171 + return nil, fmt.Errorf("get record failed with status %d: %s", resp.StatusCode, bodyStr) 157 172 } 158 173 159 174 var result Record
+2 -1
pkg/atproto/manifest_store.go
··· 3 3 import ( 4 4 "context" 5 5 "encoding/json" 6 + "errors" 6 7 "fmt" 7 8 "maps" 8 9 "strings" ··· 47 48 _, err := s.client.GetRecord(ctx, ManifestCollection, rkey) 48 49 if err != nil { 49 50 // If not found, return false without error 50 - if err.Error() == "record not found" { 51 + if errors.Is(err, ErrRecordNotFound) { 51 52 return false, nil 52 53 } 53 54 return false, err
+3 -23
pkg/atproto/profile.go
··· 3 3 import ( 4 4 "context" 5 5 "encoding/json" 6 + "errors" 6 7 "fmt" 7 8 ) 8 9 ··· 63 64 return nil 64 65 } 65 66 66 - // isNotFoundError checks if an error is a 404 not found error 67 + // isNotFoundError checks if an error is a record not found error 67 68 func isNotFoundError(err error) bool { 68 - // This is a simple check - in practice, you might need to parse the error more carefully 69 - if err == nil { 70 - return false 71 - } 72 - errStr := err.Error() 73 - return contains(errStr, "404") || contains(errStr, "not found") || contains(errStr, "RecordNotFound") 74 - } 75 - 76 - // contains checks if a string contains a substring (case-insensitive helper) 77 - func contains(s, substr string) bool { 78 - return len(s) >= len(substr) && (s == substr || len(s) > len(substr) && 79 - (s[:len(substr)] == substr || s[len(s)-len(substr):] == substr || 80 - findSubstring(s, substr))) 81 - } 82 - 83 - func findSubstring(s, substr string) bool { 84 - for i := 0; i <= len(s)-len(substr); i++ { 85 - if s[i:i+len(substr)] == substr { 86 - return true 87 - } 88 - } 89 - return false 69 + return errors.Is(err, ErrRecordNotFound) 90 70 }
+2 -1
pkg/hold/registration.go
··· 3 3 import ( 4 4 "context" 5 5 "encoding/json" 6 + "errors" 6 7 "fmt" 7 8 "log" 8 9 "net/http" ··· 288 289 record, err := client.GetRecord(ctx, atproto.HoldCrewCollection, "allow-all") 289 290 if err != nil { 290 291 // Record doesn't exist 291 - if strings.Contains(err.Error(), "not found") { 292 + if errors.Is(err, atproto.ErrRecordNotFound) { 292 293 return false, nil 293 294 } 294 295 return false, fmt.Errorf("failed to get crew record: %w", err)