# Finding which var is an invalid type when initialising a struct

**URL:** <https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734>\
**Category:** General Usage\
**Tags:** question\
**Created:** [March 30, 2022, 11:42am UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734 "2022-03-30T11:42:11Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![this\_josh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/this_josh/32/42679_2.png) [@this\_josh](https://discourse.julialang.org/u/this_josh)\
**Post date:** [March 30, 2022, 11:42am UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/1 "2022-03-30T11:42:12Z")

</div>

I have a function which loads some CSVs, and then constructs a large Struct, sometimes these CSVs contain information as Strings when they should be numerical. Currently When initialising a struct I get the unhelpful error message:

```julia
ERROR: MethodError: Cannot `convert` an object of type InlineStrings.String31 to an object of type Int64

```

**Is it possible for Julia to tell me which variable is of an invalid type?** For example

```julia
struct Foo
    a::Int64
    b::Int64
    c::Int64
    d::Int64
end

# all good
Foo(1,2,3,4) 

```

Instead of

```julia
Foo(1,2,3, "a")
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int64
Closest candidates are:
  convert(::Type{T}, ::Ptr) where T<:Integer at ~/.julia/juliaup/julia-1.7.2+0~x64/share/julia/base/pointer.jl:23
  convert(::Type{IT}, ::GeometryBasics.OffsetInteger) where IT<:Integer at ~/.julia/packages/GeometryBasics/3PqdK/src/offsetintegers.jl:40
  convert(::Type{T}, ::Base.TwicePrecision) where T<:Number at ~/.julia/juliaup/julia-1.7.2+0~x64/share/julia/base/twiceprecision.jl:262
  ...
Stacktrace:
 [1] Foo(a::Int64, b::Int64, c::Int64, d::String)
   @ Main ./REPL[20]:2
 [2] top-level scope
   @ REPL[22]:1

```

Can I get something like this

```julia
# Invalid string
Foo(1,2,3, "a")
ERROR: "a" was provided for Foo.d, this cannot be converted to Int64

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [March 30, 2022, 12:01pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/2 "2022-03-30T12:01:10Z")

</div>

I’m not sure if there is any package for that (seems something nice to have). But you could do it by hand using this:

```julia
julia> struct Foo
           a::Int
           b::Int
           function Foo(a,b)
               @assert a isa Int "a is not an integer!"
               @assert b isa Int "b is not an integer!"
               new(a,b)
           end
       end

julia> Foo(1,2)
Foo(1, 2)

julia> Foo(1,"a")
ERROR: AssertionError: b is not an integer!
Stacktrace:
 [1] Foo(a::Int64, b::String)
   @ Main ./REPL[1]:6
 [2] top-level scope
   @ REPL[3]:1

```

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [March 30, 2022, 12:05pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/3 "2022-03-30T12:05:45Z")

</div>

> [@this\_josh](#):
>
> Can I get something like this

But you do already get that information, as part of the stack trace?

> [@this\_josh](#):
>
> ```julia
> Stacktrace:
> [1] Foo(a::Int64, b::Int64, c::Int64, d::String)
> @ Main ./REPL[20]:2
> 
> ```

This already says that you tried to call `Foo` with three `Int` and one `String` argument. It’s just that the `MethodError` can’t see that stacktrace, since the method that fails is when it tries to `convert` the `String` to the `Int`.

> [@lmiq](#):
>
> But you could do it by hand using this:

You can make it throw the `MethodError` by specifying the types in the constructor (no need for `@assert`, which is _not_ guaranteed to actually be used and shouldn’t be relied upon for correctness of an algorithm, as documented):

```julia
julia> struct Foo
           a::Int64
           b::Int64
           c::Int64
           d::Int64
           Foo(a::Int, b::Int, c::Int, d::Int) = new(a,b,c,d)
       end

julia> Foo(1,2,3,"a")
ERROR: MethodError: no method matching Foo(::Int64, ::Int64, ::Int64, ::String)
Closest candidates are:
  Foo(::Int64, ::Int64, ::Int64, ::Int64) at REPL[1]:6
Stacktrace:
 [1] top-level scope
   @ REPL[2]:100

```

though that will prevent something like `Foo(0x0, 0x1, 0x2, 0x3)` (i.e. passing all `UInt8`) as well, since now the default constructor that calls `convert` is overwritten.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [March 30, 2022, 12:18pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/4 "2022-03-30T12:18:13Z")

</div>

If the purpose of the error message is to be clearer, particularly for _users_, I think that providing a better error message is nice anyway, these stack traces can be hard to follow.

Given the warning about the misuse of `@assert` there, you can use:

```julia
julia> struct Foo
           a::Int
           b::Int
           function Foo(a,b)
               a isa Int || error("a is not an integer!")
               b isa Int || error("b is not an integer!")
               new(a,b)
           end
       end

julia> Foo(1,"a")
ERROR: b is not an integer!
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] Foo(a::Int64, b::String)
   @ Main ./REPL[1]:6
 [3] top-level scope
   @ REPL[2]:1

```

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [March 30, 2022, 12:31pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/5 "2022-03-30T12:31:37Z")

</div>

> [@lmiq](#):
>
> If the purpose of the error message is to be clearer, particularly for _users_ , I think that providing a better error message is nice anyway, these stack traces can be hard to follow.

I’d check for `a isa Integer`, since `new` will still try to `convert(Int, a)`. Additionally, `ArgumentError` is a little cleaner still than the generic `error` function and throwing explicitly also doesn’t clobber the stacktrace:

```julia
julia> struct Foo
           a::Int64
           b::Int64
           function Foo(a,b)
               a isa Integer || throw(ArgumentError("`a` is not an Integer!"))
               b isa Integer || throw(ArgumentError("`b` is not an Integer!"))
               new(a,b)
           end
       end

julia> Foo(0x0,"a")
ERROR: ArgumentError: `b` is not an Integer!
Stacktrace:
 [1] Foo(a::UInt8, b::String)
   @ Main ./REPL[2]:6
 [2] top-level scope
   @ REPL[3]:1

julia> Foo(0x0,0x1)
Foo(0, 1)

```

I’m still in the camp that reading a stacktrace & getting to grasps with what a `MethodError` means is a necessary skill when debugging julia, but yeah, giving a better error message is definitely nice.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [March 30, 2022, 12:35pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/6 "2022-03-30T12:35:10Z")

</div>

> [@Sukera](#):
>
> means is a necessary skill when debugging julia

If you a developer, surely, but there are package users out there as well, who will just find that unintelligible and find something else to use.

---

<div class="post-metadata">

**Author:** ![this\_josh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/this_josh/32/42679_2.png) [@this\_josh](https://discourse.julialang.org/u/this_josh)\
**Post date:** [March 30, 2022, 12:48pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/7 "2022-03-30T12:48:45Z")

</div>

In this minimal example you’re correct about the stack trace, however, in my actual use case this information isn’t available. I’ve created a [more complex and representative minimal working example](https://github.com/this-josh/julia-struct-example)

```julia
julia> using ex
julia> read_files(true)
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Float64
Closest candidates are:
  convert(::Type{T}, ::T) where T<:Number at ~/.julia/juliaup/julia-1.7.2+0~x64/share/julia/base/number.jl:6
  convert(::Type{T}, ::Number) where T<:Number at ~/.julia/juliaup/julia-1.7.2+0~x64/share/julia/base/number.jl:7
  convert(::Type{T}, ::Base.TwicePrecision) where T<:Number at ~/.julia/juliaup/julia-1.7.2+0~x64/share/julia/base/twiceprecision.jl:262
  ...
Stacktrace:
 [1] setindex!
   @ ./array.jl:905 [inlined]
 [2] read_files(fail::Bool)
   @ ex ~/expack/ex/src/loader.jl:6
 [3] top-level scope
   @ REPL[2]:1

```

The struct causing the problem is till `Foo`, but `Foo` isn’t in the stack trace

---

<div class="post-metadata">

**Author:** ![this\_josh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/this_josh/32/42679_2.png) [@this\_josh](https://discourse.julialang.org/u/this_josh)\
**Post date:** [March 30, 2022, 12:55pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/8 "2022-03-30T12:55:29Z")

</div>

Thank you for your solution(s), the major downside of all the error variations is that they require code duplication. I’ve also just checked on the more complex minimal working example and this approach still doesn’t identify which argument is causing the problem, see the previously linked repo.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [March 30, 2022, 1:01pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/9 "2022-03-30T13:01:25Z")

</div>

I didn’t run the test, but at least you missed the `new(a,b,c,d)` here:

```julia
using Parameters
using SparseArrays

@with_kw mutable struct Foo
    a::Int64
    b::Int64
    c::Int64
    d::SparseArrays.SparseMatrixCSC{Int64,Int64}
    function Foo(a, b, c, d)
        d isa SparseArrays.SparseMatrixCSC{Int64,Int64} || throw(ArgumentError("`b` is not an Integer!"))
        new(a,b,c,d) # <<<< here
    end
end

```

---

<div class="post-metadata">

**Author:** ![this\_josh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/this_josh/32/42679_2.png) [@this\_josh](https://discourse.julialang.org/u/this_josh)\
**Post date:** [March 30, 2022, 1:08pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/10 "2022-03-30T13:08:15Z")

</div>

Thanks, I’ve corrected this. It hasn’t changed the behaviour.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [March 30, 2022, 1:13pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/11 "2022-03-30T13:13:48Z")

</div>

You are getting the error in the previous line, that is:

[https://github.com/this-josh/julia-struct-example/blob/bb3966fb8d37d8d607c5193c21e5377eb0b2a7f2/src/loader.jl#L6](https://github.com/this-josh/julia-struct-example/blob/bb3966fb8d37d8d607c5193c21e5377eb0b2a7f2/src/loader.jl#L6)

because `bad` is an array of floats and you are trying to assign a string to one of its elements.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [March 30, 2022, 1:15pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/12 "2022-03-30T13:15:55Z")

</div>

> [@this\_josh](#):
>
> The struct causing the problem is till `Foo` , but `Foo` isn’t in the stack trace

Because the error isn’t happening in the creation of `Foo`, but in this line of your `loader.jl`:

> `bad[5, 5] = "hello" `

as your stacktrace shows:

> [@this\_josh](#):
>
> ```julia
> [2] read_files(fail::Bool)
> @ ex ~/expack/ex/src/loader.jl:6
> 
> ```

which points to line 6 of the file in question.

---

<div class="post-metadata">

**Author:** ![this\_josh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/this_josh/32/42679_2.png) [@this\_josh](https://discourse.julialang.org/u/this_josh)\
**Post date:** [March 30, 2022, 1:26pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/13 "2022-03-30T13:26:56Z")

</div>

🤦‍♂️ Apologies for the consistent mistakes. Reverting to the original question stacks are great, but for struts with a lot of fields and complex data types it is not trivial deciphering which is the problematic argument. When using something like [pydantic](https://pydantic-docs.helpmanual.io) you are notified of which arguments are problematic which is a huge help when debugging. Following from your responses it seems the only way to get this functionality is with a constructor which tests each arguments type, unfortunately this produces a lot of code repetition.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [March 30, 2022, 1:32pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/14 "2022-03-30T13:32:29Z")

</div>

That clearly the place of a small macro/package. An experienced macro programmer probably can get that done in a few minutes. That would be useful, IMO.

edit: actually you don’t need a macro, but this probably doesn not play well with `Parameters`:

```julia
julia> struct Foo
           a::Int
           b::Float64
           function Foo(args...)
               names = collect(fieldnames(Foo))
               types = collect(fieldtypes(Foo))
               i = 0
               for arg in args
                   i += 1
                   if typeof(arg) != types[i]
                       error("$(names[i]) is not of type $(types[i])")
                   end
               end
               new(args...)
           end
       end

julia> Foo(1,2.0)
Foo(1, 2.0)

julia> Foo(1,"a")
ERROR: b is not of type Float64
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] Foo(::Int64, ::Vararg{Any})
   @ Main ./REPL[5]:11
 [3] top-level scope
   @ REPL[7]:1

```

---

<div class="post-metadata">

**Author:** ![this\_josh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/this_josh/32/42679_2.png) [@this\_josh](https://discourse.julialang.org/u/this_josh)\
**Post date:** [March 30, 2022, 1:41pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/15 "2022-03-30T13:41:39Z")

</div>

Nice solution, perhaps that could inspire a Parameter.jl PR? As @Sukera suggested you may want to `throw(ArgumentError())`

Thank you both

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [March 30, 2022, 1:53pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/16 "2022-03-30T13:53:25Z")

</div>

> [@this\_josh](#):
>
> Nice solution, perhaps that could inspire a Parameter.jl PR?

As mentioned above, this case is _exactly_ what `MethodError` is for (worse: it creates a method that pretends to work as usual, but then behaves unpredictably & breaks with the rest of the julia ecosystem. Should there be better error messages for `MethodError` in the future, your code won’t benefit from that). Everything here works as designed and the code proposed above just poorly emulates that behavior because it skips the possible `convert` entirely. You’d have to limit your arguments to ones that are `convert`ible, which you as the author may not even know about.

Yes it may be harder to follow in some cases, but dealing with this problem _generically_ is much harder and has more edge cases than you may think of initially.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [March 30, 2022, 2:01pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/17 "2022-03-30T14:01:24Z")

</div>

I think this can be thought as a more pedestrian and simple problem. I don’t see how adding a type check for a custom structure can “behave unpredictably and break the julia ecosystem”.

Clearly I’m not claiming that I will add PR anywhere with that solution or any other, but I think something like that is perfectly fine for helping users of a specific package to deal with the interface that it exposes for data input.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [March 30, 2022, 2:07pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/18 "2022-03-30T14:07:10Z")

</div>

Sorry, I may have worded this weirdly - I am not saying that it breaks the ecosystem as a whole, it breaks with the _behavior_ of the rest of the ecosystem, in that it _doesn’t_ throw a `MethodError`. More people adopting this hand-rolled approach means a lot of different error messages & implementations of dealing with this, which could be solved just as well by simply annotating the types in the constructor (which would result in the `MethodError` again). It’s core to how julia works, so hiding it/trying to get away from it would imo create more problems & confusion than it may initially solve, once users start to use other packages that just don’t use this same approach (a package doesn’t live in isolation after all).

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [March 30, 2022, 2:31pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/19 "2022-03-30T14:31:17Z")

</div>

I kinda disagree with @Sukera, for the following reasons:

1. The exception type [`ArgumentError` description](https://docs.julialang.org/en/v1/base/base/#Core.ArgumentError) matches the case.
2. The exception type `ArgumentError` is already used pervasively in `Base`: [https://github.com/JuliaLang/julia/search?q=ArgumentError](https://github.com/JuliaLang/julia/search?q=ArgumentError)
3. Anecdotal evidence: I never had a problem with people using `ArgumentError`, but I (and other people that I tried to help on discourse) had problems with a more generic function/constructor existing but a more specific signature throwing a `MethodError` and everyone is confused and running in circles because “a MethodError could not have been thrown, there is at least one method that matches the arguments that is this generic one”.

But yes, I believe the most generic exception type should not be thrown, `ArgumentError` should be used instead.

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [March 30, 2022, 2:32pm UTC](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734/20 "2022-03-30T14:32:28Z")

</div>

Ah, I also recommend looking at the [Base.Experimental.register\_error\_hint](https://docs.julialang.org/en/v1/base/base/#Base.Experimental.register_error_hint), which would probably be “the right” way to deal with the problem if it was not Experimental.

[Next page](https://discourse.julialang.org/t/finding-which-var-is-an-invalid-type-when-initialising-a-struct/78734.md?page=2)
