{"record":{"id":"00915a89ffef9d25","repo":"ipfs/kubo","slug":"expected-env-to-be-of-type-t-got-t","errorCode":null,"errorMessage":"expected env to be of type %T, got %T","messagePattern":"expected env to be of type %T, got %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/commands/cmdenv/env.go","lineNumber":29,"sourceCode":"\t\"github.com/ipfs/go-cid\"\n\tcmds \"github.com/ipfs/go-ipfs-cmds\"\n\tlogging \"github.com/ipfs/go-log/v2\"\n\t\"github.com/ipfs/kubo/commands\"\n\t\"github.com/ipfs/kubo/config\"\n\t\"github.com/ipfs/kubo/core\"\n\tcoreiface \"github.com/ipfs/kubo/core/coreiface\"\n\toptions \"github.com/ipfs/kubo/core/coreiface/options\"\n\t\"github.com/ipfs/kubo/core/node\"\n\trouting \"github.com/libp2p/go-libp2p/core/routing\"\n)\n\nvar log = logging.Logger(\"core/commands/cmdenv\")\n\n// GetNode extracts the node from the environment.\nfunc GetNode(env any) (*core.IpfsNode, error) {\n\tctx, ok := env.(*commands.Context)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"expected env to be of type %T, got %T\", ctx, env)\n\t}\n\n\treturn ctx.GetNode()\n}\n\n// GetApi extracts CoreAPI instance from the environment.\nfunc GetApi(env cmds.Environment, req *cmds.Request) (coreiface.CoreAPI, error) { //nolint\n\tctx, ok := env.(*commands.Context)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"expected env to be of type %T, got %T\", ctx, env)\n\t}\n\n\toffline, _ := req.Options[\"offline\"].(bool)\n\tif !offline {\n\t\toffline, _ = req.Options[\"local\"].(bool)\n\t\tif offline {\n\t\t\tlog.Errorf(\"Command '%s', --local is deprecated, use --offline instead\", strings.Join(req.Path, \" \"))\n\t\t}","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/core/commands/cmdenv/env.go#L11-L47","documentation":"cmdenv.GetNode asserts that the command's environment is *commands.Context so it can call GetNode(). If env is anything else (nil, a raw context, or a different runner's environment type) it returns a type-mismatch error naming both the (nil) expected pointer type and the actual dynamic type.","triggerScenarios":"Invoking a command Run function (e.g. dag export/import/put, filestore commands, p2p) with an environment that is not *cmds.Context — e.g. calling the Run/PostRun function directly in tests or tools without building the standard commands.Context.","commonSituations":"Embedding kubo commands in another CLI and passing a custom env; unit tests calling command Run funcs with context.Background() or a mock env; constructing requests manually without cmdenv wiring.","solutions":["Build the env via the normal http/rpc or daemon command path so env is *commands.Context","Wrap your node in commands.Context: &commands.Context{ConstructNode: ...} and pass that as Environment","Use client/rpc HTTP API instead of invoking core/commands Run functions directly"],"exampleFix":"// before\ncmd.Run(req, env) // env = ctx.Context()\n// after\ncctx := &commands.Context{ConstructNode: func() (*core.IpfsNode, error) { return node, nil }}\ncmd.Run(req, cctx)","handlingStrategy":"type-guard","validationCode":"if cctx, ok := env.(*commands.Context); ok {\n    node, err := cctx.GetNode()\n}","typeGuard":"func asCommandsContext(env any) (*commands.Context, bool) {\n    cctx, ok := env.(*commands.Context)\n    return cctx, ok\n}","tryCatchPattern":"node, err := cmdenv.GetNode(env)\nif err != nil {\n    return fmt.Errorf(\"command requires daemon env: %w\", err)\n}","preventionTips":["Always pass *commands.Context as Environment","In tests use the same env construction as production (commands.Context)","Never pass context.Background()/ctx.Context() as cmdenv Environment"],"tags":["env","type-mismatch","coreapi","test-harness"],"backgroundTag":"unexpected-environment-type","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"}