{"record":{"id":"67c3da898d878ed5","repo":"ipfs/kubo","slug":"expected-a-file-handle","errorCode":null,"errorMessage":"expected a file handle","messagePattern":"expected a file handle","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/commands/dag/import.go","lineNumber":119,"sourceCode":"\tvar blockCount, blockBytesCount uint64\n\n\t// remember last valid block and provide a meaningful error message\n\t// when a truncated/mangled CAR is being imported\n\timportError := func(previous blocks.Block, current blocks.Block, err error) error {\n\t\tif current != nil {\n\t\t\treturn fmt.Errorf(\"import failed at block %q: %w\", current.Cid(), err)\n\t\t}\n\t\tif previous != nil {\n\t\t\treturn fmt.Errorf(\"import failed after block %q: %w\", previous.Cid(), err)\n\t\t}\n\t\treturn fmt.Errorf(\"import failed: %w\", err)\n\t}\n\n\tit := req.Files.Entries()\n\tfor it.Next() {\n\t\tfile := files.FileFromEntry(it)\n\t\tif file == nil {\n\t\t\treturn errors.New(\"expected a file handle\")\n\t\t}\n\n\t\t// import blocks\n\t\terr = func() error {\n\t\t\t// wrap a defer-closer-scope\n\t\t\t//\n\t\t\t// every single file in it() is already open before we start\n\t\t\t// just close here sooner rather than later for neatness\n\t\t\t// and to surface potential errors writing on closed fifos\n\t\t\t// this won't/can't help with not running out of handles\n\t\t\tdefer file.Close()\n\n\t\t\tvar previous blocks.Block\n\n\t\t\t// Wrap the file to hide the io.Seeker interface.\n\t\t\t// Over the HTTP API the underlying reader is a multipart stream\n\t\t\t// that cannot seek, but boxo's ReaderFile advertises io.Seeker\n\t\t\t// anyway and returns ErrNotSupported at runtime. Hiding the","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/core/commands/dag/import.go#L101-L137","documentation":"`ipfs dag import` iterates req.Files entries and each entry must be a readable file handle (files.File). If an entry cannot be converted to a file — e.g. a directory entry, null entry, or a nonexistent stdin/pipe — the command aborts with \"expected a file handle\".","triggerScenarios":"Calling `ipfs dag import` with a directory instead of .car files; passing a named pipe/stdin entry that is not a regular stream; programmatic use of the RPC API with malformed multipart file entries.","commonSituations":"Shell glob expanding to directories; HTTP API multipart body missing the file part; using --stdin-name incorrectly.","solutions":["Pass actual .car files, not directories: `ipfs dag import dir/*.car`","Verify the file exists and is readable before importing","For the HTTP API, ensure the multipart body contains a proper file part"],"exampleFix":"// before\nipfs dag import ./car-dir\n// error: expected a file handle\n// after\nipfs dag import ./car-dir/*.car","handlingStrategy":"validation","validationCode":"// ensure each argument is a regular readable file\nfor _, p := range carPaths {\n    st, err := os.Stat(p)\n    if err != nil || st.IsDir() {\n        return fmt.Errorf(\"%s is not a file\", p)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Glob with *.car, not directory names","Check existence/readability before invoking","For RPC clients, send each CAR as a file part"],"tags":["cli","dag-import","input-validation"],"backgroundTag":"expected-file-handle","analyzedSha":"329838acdfafae224582930457efe80aa217afc0","analyzedAt":"2026-09-03T18:30:52.135Z","contentChangedAt":"2026-09-03T18:30:52.135Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}