AlistGo/alist · error

IsTruncated nil

Error message

IsTruncated nil

What it means

Thrown by the S3 driver's legacy ListObjects V1 pagination loop after a successful ListObjects call whose response body omitted the IsTruncated field. The AWS SDK models IsTruncated as a *bool, so a provider that simply does not return it yields nil, and the driver aborts instead of guessing whether more pages exist. It is a defect/quirk of S3-compatible providers rather than of real AWS S3, which always sets the field.

Source

Thrown at drivers/s3/util.go:135

		}
		for _, object := range listObjectsResult.Contents {
			if strings.HasSuffix(*object.Key, "/") {
				continue
			}
			name := path.Base(*object.Key)
			if !args.S3ShowPlaceholder && (name == getPlaceholderName(d.Placeholder) || name == d.Placeholder) {
				continue
			}
			file := &model.Object{
				//Id:        *object.Key,
				Name:     name,
				Size:     *object.Size,
				Modified: *object.LastModified,
			}
			files = append(files, model.WrapObjStorageClass(file, aws.StringValue(object.StorageClass)))
		}
		if listObjectsResult.IsTruncated == nil {
			return nil, errors.New("IsTruncated nil")
		}
		if *listObjectsResult.IsTruncated {
			marker = *listObjectsResult.NextMarker
		} else {
			break
		}
	}
	return files, nil
}

func (d *S3) listV2(prefix string, args model.ListArgs) ([]model.Obj, error) {
	prefix = getKey(prefix, true)
	files := make([]model.Obj, 0)
	var continuationToken, startAfter *string
	for {
		input := &s3.ListObjectsV2Input{
			Bucket:            &d.Bucket,
			ContinuationToken: continuationToken,

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Switch the storage config to list_version = v2 (ListObjectsV2), which uses ContinuationToken and does not depend on IsTruncated
  2. Upgrade the S3-compatible gateway (MinIO/Ceph) to a version that fully populates IsTruncated in V1 responses
  3. Patch listV1 to treat a nil IsTruncated as 'not truncated' via aws.BoolValue(listObjectsResult.IsTruncated) when the result set is smaller than the page size

Example fix

// before
if listObjectsResult.IsTruncated == nil {
	return nil, errors.New("IsTruncated nil")
}
if *listObjectsResult.IsTruncated {
	marker = *listObjectsResult.NextMarker
} else {
	break
}

// after (defensive: nil treated as end of listing)
if aws.BoolValue(listObjectsResult.IsTruncated) && listObjectsResult.NextMarker != nil {
	marker = *listObjectsResult.NextMarker
} else {
	break
}
Defensive patterns

Strategy: validation

Validate before calling

// before switching to list v1, probe the provider
out, err := s3client.ListObjects(&s3.ListObjectsInput{Bucket: aws.String(bucket), MaxKeys: aws.Int64(1)})
if err != nil { return err }
if out.IsTruncated == nil {
    // provider omits IsTruncated: use ListObjectsV2 for this storage
    return configureListVersion("v2")
}

Type guard

func hasTruncationFlag(out *s3.ListObjectsOutput) bool {
    return out != nil && out.IsTruncated != nil
}

Try / catch

// in a wrapper around List
files, err := d.List(ctx, dir, args)
if err != nil && strings.Contains(err.Error(), "IsTruncated nil") {
    log.Warn("provider omits IsTruncated; switching storage to list_version=v2")
    setStorageListVersion("v2") // next List call succeeds
    files, err = d.List(ctx, dir, args)
}

Prevention

When it happens

Trigger: Listing a bucket with list_version=v1 against an S3-compatible endpoint (some MinIO/Ceph/vendor gateways) that returns <ListBucketResult> without <IsTruncated>. The very first page (or any later page) then triggers this error before pagination can continue.

Common situations: Self-hosted MinIO or Ceph RGW endpoints, NAS vendor 'S3' services, or older gateway firmware that implement the V1 API incompletely; also misconfigured custom endpoint_url pointing at such a gateway. Real AWS, and list_version v2 (ListObjectsV2 uses different pagination fields), never hit it.

Related errors


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