usememos/memos · error
invalid uid
Error message
invalid uid
What it means
Returned by Store.CreateMemo when the supplied memo UID does not match base.UIDMatcher: ^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,34}[a-zA-Z0-9])?$ — 1 to 36 characters, must start and end with a letter or digit, and may contain only letters, digits and dashes in between. UIDs become resource names (memos/<uid>), so the format is enforced before the row reaches any database driver. This is a normal API-level validation error, not a startup failure.
Source
Thrown at store/memo.go:111
type UpdateMemo struct {
ID int32
UID *string
CreatedTs *int64
UpdatedTs *int64
RowStatus *RowStatus
Content *string
Visibility *Visibility
Pinned *bool
Payload *storepb.MemoPayload
}
type DeleteMemo struct {
ID int32
}
func (s *Store) CreateMemo(ctx context.Context, create *Memo) (*Memo, error) {
if !base.UIDMatcher.MatchString(create.UID) {
return nil, errors.New("invalid uid")
}
return s.driver.CreateMemo(ctx, create)
}
func (s *Store) ListMemos(ctx context.Context, find *FindMemo) ([]*Memo, error) {
return s.driver.ListMemos(ctx, find)
}
func (s *Store) GetMemo(ctx context.Context, find *FindMemo) (*Memo, error) {
list, err := s.ListMemos(ctx, find)
if err != nil {
return nil, err
}
if len(list) == 0 {
return nil, nil
}
memo := list[0]View on GitHub (pinned to 14d757ce1f)
Solutions
- Send a uid of 1-36 characters using only [a-zA-Z0-9-], starting and ending with a letter or digit (replace '_' with '-').
- If you do not need a custom uid, omit the field and let the server generate one.
- If parsing a resource name like "memos/abc123", pass only the segment after the slash.
Example fix
// before
memo, err := store.CreateMemo(ctx, &store.Memo{ UID: "my_note_2024!", Content: &content })
// after
memo, err := store.CreateMemo(ctx, &store.Memo{ UID: "my-note-2024", Content: &content }) Defensive patterns
Strategy: validation
Validate before calling
// Go callers: validate before CreateMemo
var uidMatcher = regexp.MustCompile(`^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,34}[a-zA-Z0-9])?$`)
if create.UID != "" && !uidMatcher.MatchString(create.UID) {
return errors.New("uid must be 1-36 chars of [a-zA-Z0-9-], alphanumeric at both ends")
}
memo, err := s.CreateMemo(ctx, create) Type guard
func isValidMemoUID(uid string) bool {
ok := len(uid) >= 1 && len(uid) <= 36
if !ok {
return false
}
for i, r := range uid {
alnum := (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9')
if i == 0 || i == len(uid)-1 {
if !alnum {
return false
}
} else if !alnum && r != '-' {
return false
}
}
return true
} Try / catch
// In service layer: map store validation errors to InvalidArgument
memo, err := s.Store.CreateMemo(ctx, create)
if err != nil {
if strings.Contains(err.Error(), "invalid uid") {
return nil, status.Errorf(codes.InvalidArgument, "uid must match [a-zA-Z0-9-]{1,36} with alphanumeric ends")
}
return nil, status.Errorf(codes.Internal, "failed to create memo")
} Prevention
- Let the server generate UIDs unless you truly need stable slugs (e.g. imports).
- When importing, sanitize foreign ids: lowercase, replace '_' and '.' with '-', trim dashes, truncate to 36.
- Pass the bare uid, not the resource name 'memos/<uid>'.
When it happens
Trigger: Calling the memo-creation API path that sets a custom uid with an empty string, a uid containing underscores/dots/slashes, a uid longer than 36 characters, or one starting/ending with a dash. Auto-generated UIDs that collide with these rules (rare) would surface the same error.
Common situations: Clients importing notes from another system and reusing foreign slugs with underscores; trimming/normalizing loops that produce an empty uid; resource-name parsing that passes 'memos/abc' as the uid instead of 'abc'.
Related errors
- InvalidArgument
- Internal
- SMTP host is required
- SMTP port must be between 1 and 65535
- from email is required
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/49b70063b65505fd.
Report an issue: GitHub.