Wire 报 “provider ... returns error but injection not allowed to fail“ 怎么排查错误返回值?
Wire 报 provider ... returns error but injection not allowed to fail 怎么排查错误返回值【免费下载链接】wireCompile-time Dependency Injection for Go项目地址: https://gitcode.com/GitHub_Trending/wi/wire用 Wire 做依赖注入代码生成时在包目录下运行wire命令可能会看到类似这样的错误example.com/foo/wire.go:x:y: inject injectFoo: provider for example.com/foo.Foo returns error but injection not allowed to fail这不是运行时错误而是wire命令在生成wire_gen.go时给出的代码生成错误。它的含义很明确你放进wire.Build的某个 provider 会返回error但对应的 injector 函数签名却没有声明返回errorWire 无法决定这个错误该交给谁处理于是拒绝生成代码。本文按读懂错误 → 定位 injector 签名 → 修正签名 → 重新生成并验证的路径排查这个问题。读懂错误信息的两个部分这条错误由两部分定位信息组成排查时先按这两部分缩小范围inject injectFoo出问题的 injector 函数名。仓库测试用例 InjectorMissingError 中的 injector 就叫injectFoo报错时这一处会打印出它所在文件的位置如example.com/foo/wire.go的行、列号。provider for example.com/foo.Foo returns error具体是哪个 provider 的输出类型无法被 injector 接收。这里打印的是 provider 提供的类型全路径名。错误本身的生成逻辑在 internal/wire/wire.go 中Wire 在生成 injector 时逐个检查依赖链上的调用如果某个调用带有错误返回值provider 返回(T, error)而 injector 签名没有error返回值就报出这条错误并终止生成。对照 User Guide 可以确认这是预期行为provider 允许返回 error文档给出的ProvideBaz(ctx, bar) (Baz, error)示例而 injector 也声明可以返回 error文档中的initializeBaz(ctx context.Context) (foobarbaz.Baz, error)两者配套时 Wire 才会生成检查err的代码。用仓库测试用例还原触发场景InjectorMissingError 测试用例完整展示了触发条件type Foo int func provideFoo() (Foo, error) { return Foo(42), nil }providerprovideFoo的签名返回(Foo, error)。而同一包里的 injector见 wire.go是//build wireinject package main import ( github.com/google/wire ) func injectFoo() Foo { // provideFoo returns an error, but injectFoo does not. wire.Build(provideFoo) return Foo(0) }注意 injector 只返回Foo没有返回error但它通过wire.Build(provideFoo)引入了一个会返回 error 的 provider。该用例的预期错误输出记录在 wire_errs.txtexample.com/foo/wire.go:x:y: inject injectFoo: provider for example.com/foo.Foo returns error but injection not allowed to fail所以排查时的第一个动作是打开错误中点名的 injector 文件本例是wire.go看它的返回值列表里有没有error再看wire.Build里传入的每个 provider或 provider set 展开后的 provider的签名找到那个多返回了error的函数。修复让 injector 声明返回 error解决办法就是让 injector 的签名接住这个错误给 injector 增加error返回值然后重新运行wire。仓库中的 ReturnError 测试用例就是同一组 provider 的正确写法//build wireinject package main import ( github.com/google/wire ) func injectFoo() (Foo, error) { wire.Build(Set) return 0, nil }provider 仍然是返回(Foo, error)的provideFoo只是 injector 签名从injectFoo() Foo改成了injectFoo() (Foo, error)。Tutorial 的 Making Changes with Wire 一节也演示了同样做法把InitializeEvent从只返回Event改为返回(Event, error)后重新运行wire生成代码里就自动出现了对 provider 错误的检查和提前返回。这里有两个细节要保留不要顺手删掉injector 文件头部的//build wireinject构建标签。它保证这份 stub 文件不参与最终构建stub 的return Foo(0)之类的返回值只是占位生成时会被忽略wire_gen.go生成后用go generate重新生成即可不需要每次手动跑wireUser Guide 与 Tutorial 都说明了这个流程。验证修复是否生效在 injector 所在包目录运行wire判断修复是否完成看三件事命令不再输出returns error but injection not allowed to fail生成过程正常结束包目录下生成或更新了wire_gen.go打开wire_gen.go确认生成代码对 provider 的错误做了处理。以 ReturnError 用例期望生成的 wire_gen.go 为准func injectFoo() (Foo, error) { foo, err : provideFoo() if err ! nil { return 0, err } return foo, nil }生成函数会先接收 provider 的err非空时把错误原样上抛给 injector 的调用方这正是 Tutorial 里 Wire has detected that theNewEventprovider may fail 所描述的生成行为。如果想进一步确认运行期行为ReturnError 测试用例还附带了程序输出示例见 program_out.txt0 true这是该用例文档记录的示例结果provideFoo返回错误there is no Foo时injector 返回零值和该错误。把它当作文档示例理解即可它不是你要在任何项目里核对的固定输出——你只需确认自己的调用方能够收到并处理 injector 返回的error。边界说明这条错误只在代码生成阶段出现发生在运行wire或go generate时与运行你的 Go 程序无关错误信息中打印的类型是 provider 的输出类型全路径如example.com/foo.Foo如果 provider set 较大可以顺着这个类型名反查是哪个 provider 提供的它如果 provider 的 error 本来就不该被传播业务上它永远返回nil错误仓库文档给出的标准解法仍是让 injector 返回error并在生成代码中检查文档中没有描述忽略某个 provider 错误的机制不要自行在 stub 里删改生成代码。完成以上步骤后wire命令正常生成wire_gen.go、生成代码中包含对 provider 错误的检查即表示这个报错已按 Wire 的预期处理方式解决。【免费下载链接】wireCompile-time Dependency Injection for Go项目地址: https://gitcode.com/GitHub_Trending/wi/wire创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考