usememos/memos · error
Internal
Internal
Error message
invalid uid
What it means
Store.CreateAttachment validates the attachment UID against base.UIDMatcher (^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,34}[a-zA-Z0-9])?$) before delegating to the DB driver. The error means create.UID is empty, longer than 36 chars, or contains characters other than alphanumerics and inner hyphens. It fails fast before any SQL runs.
Source
Thrown at store/attachment.go:92
const (
thumbnailCacheFolder = ".thumbnail_cache"
motionCacheFolder = ".motion_cache"
)
type deleteAttachmentStorageFailpointKey struct{}
// ErrDeleteAttachmentStorageFailpoint is returned by the test-only attachment storage failpoint.
var ErrDeleteAttachmentStorageFailpoint = errors.New("delete attachment storage failpoint")
// WithDeleteAttachmentStorageFailpoint forces DeleteAttachmentStorage to return a failpoint error.
func WithDeleteAttachmentStorageFailpoint(ctx context.Context) context.Context {
return context.WithValue(ctx, deleteAttachmentStorageFailpointKey{}, true)
}
func (s *Store) CreateAttachment(ctx context.Context, create *Attachment) (*Attachment, error) {
if !base.UIDMatcher.MatchString(create.UID) {
return nil, errors.New("invalid uid")
}
return s.driver.CreateAttachment(ctx, create)
}
func (s *Store) ListAttachments(ctx context.Context, find *FindAttachment) ([]*Attachment, error) {
// Set default limits to prevent loading too many attachments at once
shouldApplyDefaultLimit := find.Limit == nil && find.MemoID == nil && len(find.MemoIDList) == 0 && !find.SkipDefaultLimit
if shouldApplyDefaultLimit && find.GetBlob {
// When fetching blobs, we should be especially careful with limits
defaultLimit := 10
find.Limit = &defaultLimit
} else if shouldApplyDefaultLimit {
// Even without blobs, let's default to a reasonable limit
defaultLimit := 100
find.Limit = &defaultLimit
}
return s.driver.ListAttachments(ctx, find)View on GitHub (pinned to 14d757ce1f)
Solutions
- Generate UIDs as short alphanumeric strings, e.g. uuid.NewString() with hyphens removed/encoded or a nanoid restricted to [a-zA-Z0-9-]
- Validate the UID with the same regex before calling CreateAttachment
- Trim and re-check length (1-36 chars) if UIDs come from user input
Example fix
// before
uid := rawFilename // "my file (1).png"
// after
uid := shortuuid.New() // alphanumeric, matches ^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,34}[a-zA-Z0-9])?$ Defensive patterns
Strategy: validation
Validate before calling
uidRe := regexp.MustCompile(`^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,34}[a-zA-Z0-9])?$`)
if !uidRe.MatchString(att.UID) {
return fmt.Errorf("invalid attachment uid %q", att.UID)
}
_, err := store.CreateAttachment(ctx, att) Type guard
func isValidUID(uid string) bool {
return base.UIDMatcher.MatchString(uid)
} Prevention
- Generate UIDs from a restricted alphabet (alphanumerics plus inner hyphens, max 36 chars)
- Never derive UIDs from raw filenames; sanitize first
When it happens
Trigger: CreateAttachment called with an unset UID, a UID starting or ending with '-', exceeding 36 characters, or containing '_', '.', '/', spaces, or other special characters.
Common situations: Using a UUID with dashes at the edges or underscores instead of hyphens; passing a filename as UID; generating IDs with a random-string helper that includes symbols; forgetting to set UID before calling the store.
Related errors
- attachment is missing
- attachment payload is missing
- S3 object payload is missing
- S3 object key is missing
- GENERAL instance setting is required
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/f6518fa9b72d8396.
Report an issue: GitHub.