Skip to content

errors.As fails for interpreted concrete error types due to reflect/type identity mismatch #1716

@yrm006

Description

@yrm006

The following program sample.go triggers an unexpected result

package main

  import (
  	"fmt"

  	"github.com/traefik/yaegi/interp"
  	"github.com/traefik/yaegi/stdlib"
  )

  func main() {
  	i := interp.New(interp.Options{})
  	i.Use(stdlib.Symbols)

  	src := "" +
  		"import (\"errors\"; \"fmt\")\n" +
  		"type MyErr struct{}\n" +
  		"func (e *MyErr) Error() string { return \"x\" }\n" +
  		"func F() bool {\n" +
  		"  err := fmt.Errorf(\"wrap: %w\", &MyErr{})\n" +
  		"  var target *MyErr\n" +
  		"  return errors.As(err, &target)\n" +
  		"}\n"

  	if _, err := i.Eval(src); err != nil {
  		panic(err)
  	}
  	v, err := i.Eval("F()")
  	fmt.Printf("v=%v err=%v\n", v, err)
  }

Expected result

errors.As should behave like compiled Go for interpreted error types.

  In the repro:
  - errors.As(fmt.Errorf("wrap: %w", &MyErr{}), &target)
  should return true
  - target should be set to the wrapped *MyErr
  - no panic/error should occur

Got

errors.As does not match compiled Go behavior.

  In the repro:
  - errors.As(fmt.Errorf("wrap: %w", &MyErr{}), &target)
  does not return true
  - instead evaluation fails with:
    errors: *target must be interface or implement error

Yaegi Version

v0.16.1

Additional Notes

This reproduces with pure yaegi (interp.New(...) + stdlib.Symbols) and does not depend on any host integration.

The issue appears to be in interpreted type / reflect identity handling rather than in %w unwrapping itself, because:

  • var err error = &MyErr{} works
  • errors.As(err, &targetErrorInterface) works
  • but errors.As(err, &targetConcreteInterpretedType) fails

Related observation:

  • reflect.TypeOf((*MyErr)(nil)).Implements(error) evaluates to false in interpreted code
  • interpreted interface types appear as interp.valueInterface

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions