AlistGo/alist · error

failed to EncryptData: %w

Error message

failed to EncryptData: %w

What it means

Thrown by Crypt.Put when the rclone crypt cipher fails to wrap the input stream with EncryptData. EncryptData builds an encrypting reader over the file streamer; it fails when the cipher was constructed with incompatible parameters for streaming encryption or when the input stream cannot be adapted (e.g. nil/invalid streamer characteristics after the path already resolved fine). The upload aborts before any data reaches the remote.

Source

Thrown at drivers/crypt/driver.go:376

func (d *Crypt) Remove(ctx context.Context, obj model.Obj) error {
	remoteActualPath, err := d.getActualPathForRemote(obj.GetPath(), obj.IsDir())
	if err != nil {
		return fmt.Errorf("failed to convert path to remote path: %w", err)
	}
	return op.Remove(ctx, d.remoteStorage, remoteActualPath)
}

func (d *Crypt) Put(ctx context.Context, dstDir model.Obj, streamer model.FileStreamer, up driver.UpdateProgress) error {
	dstDirActualPath, err := d.getActualPathForRemote(dstDir.GetPath(), true)
	if err != nil {
		return fmt.Errorf("failed to convert path to remote path: %w", err)
	}

	// Encrypt the data into wrappedIn
	wrappedIn, err := d.cipher.EncryptData(streamer)
	if err != nil {
		return fmt.Errorf("failed to EncryptData: %w", err)
	}

	// doesn't support seekableStream, since rapid-upload is not working for encrypted data
	streamOut := &stream.FileStream{
		Obj: &model.Object{
			ID:       streamer.GetID(),
			Path:     streamer.GetPath(),
			Name:     d.cipher.EncryptFileName(streamer.GetName()),
			Size:     d.cipher.EncryptedSize(streamer.GetSize()),
			Modified: streamer.ModTime(),
			IsFolder: streamer.IsDir(),
		},
		Reader:            wrappedIn,
		Mimetype:          "application/octet-stream",
		WebPutAsTask:      streamer.NeedStore(),
		ForceStreamUpload: true,
		Exist:             streamer.GetExist(),
	}

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Re-enter password and salt in the admin UI and re-save the crypt storage so a fresh cipher is built
  2. Upgrade AList to a consistent version (bundled rclone library matches driver code)
  3. Check the wrapped error message — 'bad password' style errors mean credentials; stream errors mean the FileStreamer setup
  4. Re-create the crypt storage if the existing record keeps failing after credential re-entry
Defensive patterns

Strategy: try-catch

Validate before calling

// Before upload, verify the cipher works on a tiny buffer
if _, err := d.cipher.EncryptData(bytes.NewReader([]byte("probe"))); err != nil {
    return fmt.Errorf("cipher unusable, re-enter credentials: %w", err)
}

Try / catch

if err := d.Put(ctx, dstDir, streamer, up); err != nil {
    if strings.Contains(err.Error(), "failed to EncryptData") {
        // cipher/credential problem: re-save storage with fresh password+salt, then retry upload
        return fmt.Errorf("encryption failed, refresh crypt credentials and retry: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Uploading a file through the crypt mount when the cipher's configuration makes stream encryption fail — most commonly a corrupted or wrong-version password/salt pair that slipped past NewCipher, or an upstream rclone library change where EncryptData rejects the stream wrapper (nil reader, unsupported ReaderAt expectations).

Common situations: AList/rclone-library version mismatch after upgrade while old obscured credentials remain in the DB; storage record hand-edited so the cipher is half-initialized; very old crypt storage created by a much earlier AList version.

Related errors


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/6b87e40c13e2744b. Report an issue: GitHub.