usememos/memos · error

attachment payload is missing

Error message

attachment payload is missing

What it means

ResolveAttachmentS3Driver throws "attachment payload is missing" when the attachment exists but attachment.Payload is nil. Attachments created via legacy code paths or partially populated queries can lack the protobuf payload that identifies where the blob actually lives, so the storage driver cannot be resolved.

Source

Thrown at store/attachment.go:284

		if AttachmentNeedsInstanceStorageSetting(attachment) {
			instanceStorageSetting, err := s.GetInstanceStorageSetting(ctx)
			if err != nil {
				return nil, errors.Wrap(err, "failed to get instance storage setting")
			}
			return instanceStorageSetting, nil
		}
	}
	return nil, nil
}

// ResolveAttachmentS3Driver resolves the storage driver referenced by an S3
// attachment payload, validating the payload and supplying the instance setting.
func (s *Store) ResolveAttachmentS3Driver(ctx context.Context, attachment *Attachment) (storage.Driver, *storepb.AttachmentPayload_S3Object, error) {
	if attachment == nil {
		return nil, nil, errors.New("attachment is missing")
	}
	if attachment.Payload == nil {
		return nil, nil, errors.New("attachment payload is missing")
	}
	s3Object := attachment.Payload.GetS3Object()
	if s3Object == nil {
		return nil, nil, errors.New("S3 object payload is missing")
	}
	if s3Object.Key == "" {
		return nil, nil, errors.New("S3 object key is missing")
	}

	instanceStorageSetting, err := s.GetInstanceStorageSetting(ctx)
	if err != nil {
		return nil, nil, errors.Wrap(err, "failed to get instance storage setting")
	}
	driver, err := ResolveStorageDriver(ctx, instanceStorageSetting, s3Object.StorageId, s3Object.S3Config)
	if err != nil {
		return nil, nil, errors.Wrap(err, "failed to resolve storage driver")
	}
	return driver, s3Object, nil

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Load the attachment through the normal store finder so the payload column is included
  2. If the row genuinely has no payload, migrate or backfill payload data before using S3 features
  3. Ensure test fixtures set Payload with a valid S3Object

Example fix

// before
att := &store.Attachment{ID: id, StorageType: storepb.AttachmentStorageType_S3}
driver, obj, err := store.ResolveAttachmentS3Driver(ctx, att)
// after
att, err := store.GetAttachment(ctx, &store.FindAttachment{ID: &id}) // payload populated

driver, obj, err := store.ResolveAttachmentS3Driver(ctx, att)
Defensive patterns

Strategy: type-guard

Validate before calling

if attachment == nil || attachment.Payload == nil {
    return errors.New("attachment payload unavailable")
}

Type guard

func hasPayload(a *store.Attachment) bool {
    return a != nil && a.Payload != nil
}

Prevention

When it happens

Trigger: Passing an attachment struct loaded without its payload column, or a hand-constructed Attachment{ID: ...} value with only scalar fields set.

Common situations: Rows written before the payload column existed (schema migration gaps); queries that select a subset of columns; test fixtures that omit Payload.

Related errors


AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15). Data as JSON: /api/errors/c80ec5d890e20ae4. Report an issue: GitHub.