{"record":{"id":"be8f4b1e3ce43328","repo":"AlistGo/alist","slug":"expected-os-file-got-t","errorCode":null,"errorMessage":"expected *os.File, got %T","messagePattern":"expected \\*os\\.File, got %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/mediafire/driver.go","lineNumber":348,"sourceCode":"\treturn nil\n}\n\nfunc (d *Mediafire) Put(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) error {\n\t_, err := d.PutResult(ctx, dstDir, file, up)\n\treturn err\n}\n\nfunc (d *Mediafire) PutResult(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {\n\n\ttempFile, err := file.CacheFullInTempFile()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer tempFile.Close()\n\n\tosFile, ok := tempFile.(*os.File)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"expected *os.File, got %T\", tempFile)\n\t}\n\n\tfileHash, err := d.calculateSHA256(osFile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcheckResp, err := d.uploadCheck(ctx, file.GetName(), file.GetSize(), fileHash, dstDir.GetID())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif checkResp.Response.ResumableUpload.AllUnitsReady == \"yes\" {\n\t\tup(100.0)\n\t}\n\n\tif checkResp.Response.HashExists == \"yes\" && checkResp.Response.InAccount == \"yes\" {\n\t\tup(100.0)","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/mediafire/driver.go#L330-L366","documentation":"PutResult calls file.CacheFullInTempFile(), which returns model.File — an interface, not a concrete *os.File. Per internal/stream/stream.go, the returned value is either the stream's pre-set *os.File tmp file, OR the stream's original Reader when that Reader already implements model.File (e.g. a driver-supplied seekable file or an in-memory File implementation). The unconditional type assertion tempFile.(*os.File) fails for any non-*os.File implementation.","triggerScenarios":"Uploading via a FileStreamer whose Reader is a custom model.File (in-memory buffer, another driver's file handle, or a SeekableStream wrapping a non-temp reader) — CacheFullInTempFile returns it as-is without copying to an *os.File, and the assertion panics path fails.","commonSituations":"Server-side copy between storages, or upload pipelines where the stream originates from another driver rather than an HTTP multipart upload; also unit tests with mock FileStreamers.","solutions":["Change calculateSHA256 to accept io.Reader (SHA-256 needs only sequential reads) and drop the *os.File requirement entirely","Alternatively use the model.File interface and only Rewind/Seek when it exposes it","If an *os.File is truly required (e.g. for upload resumption), wrap non-*os.File values by copying to a temp file first"],"exampleFix":"// before: hard type assertion on an interface return\nosFile, ok := tempFile.(*os.File)\nif !ok {\n    return nil, fmt.Errorf(\"expected *os.File, got %T\", tempFile)\n}\nfileHash, err := d.calculateSHA256(osFile)\n\n// after: hash any reader, no assertion needed\nif seeker, ok := tempFile.(io.Seeker); ok {\n    _, _ = seeker.Seek(0, io.SeekStart)\n}\nfileHash, err := d.calculateSHA256(tempFile) // signature: (r io.Reader) (string, error)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// accept any model.File; only seek when possible\nfunc toHashReader(f model.File) io.Reader {\n    if s, ok := f.(io.Seeker); ok {\n        _, _ = s.Seek(0, io.SeekStart)\n    }\n    return f\n}","tryCatchPattern":"Replace the panic-prone unconditional assertion with the two-value form and a graceful path: if osFile, ok := tempFile.(*os.File); ok { use it } else { rewind via io.Seeker and hash the reader directly } — the hash never needed *os.File.","preventionTips":["Never hard-assert concrete types on interface returns from framework APIs (CacheFullInTempFile returns model.File)","Write helpers like calculateSHA256 against io.Reader, the narrowest interface you need","Test uploads with mock FileStreamers that return non-*os.File model.File implementations"],"tags":["mediafire","type-assertion","upload","interface-mismatch","go"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}