{"record":{"id":"1e95838f4aecf2cd","repo":"AlistGo/alist","slug":"unable-to-convert-file-to-object","errorCode":null,"errorMessage":"unable to convert file to Object","messagePattern":"unable to convert file to Object","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/wopan/driver.go","lineNumber":87,"sourceCode":"\t\t}\n\t\tpageNum++\n\t}\n\treturn res, nil\n}\n\nfunc (d *Wopan) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {\n\tif f, ok := file.(*Object); ok {\n\t\tres, err := d.client.GetDownloadUrlV2([]string{f.FID}, func(req *resty.Request) {\n\t\t\treq.SetContext(ctx)\n\t\t})\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &model.Link{\n\t\t\tURL: res.List[0].DownloadUrl,\n\t\t}, nil\n\t}\n\treturn nil, fmt.Errorf(\"unable to convert file to Object\")\n}\n\nfunc (d *Wopan) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {\n\tfamilyID := d.FamilyID\n\tif familyID == \"\" {\n\t\tfamilyID = d.defaultFamilyID\n\t}\n\t_, err := d.client.CreateDirectory(d.getSpaceType(), parentDir.GetID(), dirName, familyID, func(req *resty.Request) {\n\t\treq.SetContext(ctx)\n\t})\n\treturn err\n}\n\nfunc (d *Wopan) Move(ctx context.Context, srcObj, dstDir model.Obj) error {\n\tdirList := make([]string, 0)\n\tfileList := make([]string, 0)\n\tif srcObj.IsDir() {\n\t\tdirList = append(dirList, srcObj.GetID())","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/wopan/driver.go#L69-L105","documentation":"The Wopan driver's Link method expects the incoming model.Obj to be the driver's concrete *Object type (carrying FID). If it receives any other Obj implementation (a generic model.Object, a wrapped/cached object, or an object reconstructed by an upper layer), the type assertion fails and Link returns 'unable to convert file to Object'.","triggerScenarios":"Calling Link with an object not created by the Wopan driver's own List — e.g. after path caching reconstructs plain model.Object values, or code passes model.NewObj or merges objects from another driver.","commonSituations":"Meta/path-cache layers or copy tasks that re-create objects generically, third-party code driving the fs API directly, or version changes where the cache stopped preserving driver object types.","solutions":["Ensure objects passed to Link come from the Wopan driver's own List/Get so they are *Object.","Clear the path cache and retry so objects are re-fetched from the driver.","If writing custom code against model.Obj, fetch the object via the storage's Get(path) before calling Link."],"exampleFix":"// before\nobj := model.Object{Path: \"/f.txt\"}      // generic object\nlink, err := d.Link(ctx, obj, args)      // -> conversion error\n\n// after\nobj, err := d.Get(ctx, \"/f.txt\")        // returns *Object\nlink, err := d.Link(ctx, obj, args)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isWopanObject(o model.Obj) bool {\n    _, ok := o.(*driver.Object) // drivers/wopan Object\n    return ok\n}","tryCatchPattern":"obj, err := d.Get(ctx, path)\nif err != nil { return err }\nif _, ok := obj.(*Object); !ok {\n    // stale cache/generic object: force refresh via List before Link\n    return fmt.Errorf(\"refresh object via driver Get before Link\")\n}\nlink, err := d.Link(ctx, obj, args)","preventionTips":["Always source Link arguments from the driver's own List/Get","Clear path cache when conversion errors appear","Don't construct generic model.Object for driver calls in custom code"],"tags":["wopan","type-assertion","link","internal-api"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}