AlistGo/alist · error

unable to convert dir to mega n

Error message

unable to convert dir to mega n

What it means

Mega driver List was called with a dir that is not the driver's *MegaNode concrete type, so the children cannot be enumerated. The preceding log line ('can't convert: %+v') dumps the offending object. Root cause is the same class as the other Mega conversion errors: the model.Obj came from outside this driver's own object graph.

Source

Thrown at drivers/mega/driver.go:78

		for i := range nodes {
			n := nodes[i]
			if n.GetType() != mega.FILE && n.GetType() != mega.FOLDER {
				continue
			}
			if _, ok := fn[n.GetName()]; !ok {
				fn[n.GetName()] = &MegaNode{n}
			} else if sameNameObj := fn[n.GetName()]; (&MegaNode{n}).ModTime().After(sameNameObj.ModTime()) {
				fn[n.GetName()] = &MegaNode{n}
			}
		}
		res := make([]model.Obj, 0)
		for _, v := range fn {
			res = append(res, v)
		}
		return res, nil
	}
	log.Errorf("can't convert: %+v", dir)
	return nil, fmt.Errorf("unable to convert dir to mega n")
}

func (d *Mega) GetRoot(ctx context.Context) (model.Obj, error) {
	n := d.c.FS.GetRoot()
	log.Debugf("mega root: %+v", *n)
	return &MegaNode{n}, nil
}

func (d *Mega) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
	if node, ok := file.(*MegaNode); ok {

		//down, err := d.c.NewDownload(n.Node)
		//if err != nil {
		//	return nil, fmt.Errorf("open download file failed: %w", err)
		//}

		size := file.GetSize()
		resultRangeReader := func(ctx context.Context, httpRange http_range.Range) (io.ReadCloser, error) {

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Always obtain the dir from d.GetRoot() or a previous List result of the same driver instance
  2. Use GetRoot()+path resolution through the driver itself instead of synthesizing objects
  3. In frameworks, route through driver.Get(path) to re-materialize a *MegaNode before List
  4. For tests, wrap real mega nodes: construct MegaNode{n} from d.c.FS.Get(...)

Example fix

// before
if node, ok := dir.(*MegaNode); ok {
    /* list children */
}
log.Errorf("can't convert: %+v", dir)
return nil, fmt.Errorf("unable to convert dir to mega n")

// after (fail fast with actionable info)
node, ok := dir.(*MegaNode)
if !ok {
    log.Errorf("can't convert dir (type %T) to *MegaNode; re-fetch via Get(path)", dir)
    return nil, fmt.Errorf("unable to convert dir to mega n (got %T)", dir)
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Resolve dirs through the driver itself
node, ok := dir.(*MegaNode)
if !ok {
    resolved, err := d.Get(ctx, dir.GetPath())
    if err != nil { return nil, err }
    node, ok = resolved.(*MegaNode)
    if !ok { return nil, fmt.Errorf("unresolvable dir type %T", dir) }
}

Type guard

func isMegaNode(o model.Obj) bool {
    _, ok := o.(*MegaNode)
    return ok
}

Try / catch

// Guard first; only call List with verified nodes
if !isMegaNode(dir) {
    dir, err = d.Get(ctx, dir.GetPath())
    if err != nil { return nil, err }
}
return d.List(ctx, dir, args)

Prevention

When it happens

Trigger: Listing a directory object fabricated by another layer (path-based virtual object, mock, or cross-driver reference); passing model.Object value instead of *MegaNode; objects reconstructed after serialization between listing and listing a subfolder.

Common situations: File-manager frameworks that build virtual directory trees from paths; tests with generic fake objects; state restored from persistence losing the concrete node type.

Related errors


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