Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to report a line number on error when decoding custom struct? #398

Closed
GreatDanton opened this issue Aug 10, 2023 · 4 comments
Closed

Comments

@GreatDanton
Copy link

When decoding built in types, I found out that toml.Decode() method returns a ParseError which contains lots of context about the error. When unmarshalling custom structs, however, I don't know how am I supposed to obtain such context (I would like to know at least the name of the field or the line number of the user text).

func decodeConfig() (*xxx, error) {
        config := &MyConfig{}
	md, err := toml.Decode(tomlData, config)
	if err != nil {
		// pretty print errors if possible
		var pErr toml.ParseError
		if errors.As(err, &pErr) {
			return nil, fmt.Errorf("toml: config parse error: %v", pErr.ErrorWithUsage())
		}

		// err could not be cast to a toml.ParseError, which means our own unmarshaller returned an error
		// TODO: how do I get a line number or the field here? md.context is a private member.
		return nil, fmt.Errorf("toml: config parse error:\n  %v", err)
	}

         ... more code

More context about my problem:
In my case I have a custom type which tries to parse user value and return an error on invalid enum:

func (n *NodeReferenceType) UnmarshalText(text []byte) error {
	t := strings.TrimSpace(string(text))
	switch t {
	case "number_and_text":
		*n = NodeReference_NumberAndText
	case "number":
		*n = NodeReference_Number
	case "text":
		*n = NodeReference_Text
	default:
               // TODO: how can I get a line number or the name of a currently decoded key here?
               // I am trying to decode multiple fields of this same type (NodeReferenceType), so I 
               // need some way to distinguish between them.
		return fmt.Errorf("invalid reference type: available options [%s, %s, %s], but got: %q", NodeReference_NumberAndText, NodeReference_Number, NodeReference_Text, t)
	}
	return nil
}
@GreatDanton GreatDanton changed the title Report a line number on error when decoding custom struct How to report a line number on error when decoding custom struct Aug 10, 2023
@GreatDanton GreatDanton changed the title How to report a line number on error when decoding custom struct How to report a line number on error when decoding custom struct? Aug 10, 2023
@arp242
Copy link
Collaborator

arp242 commented Aug 10, 2023

It would be helpful if you can provide a full example (either as a program or test) that I can copy/paste to demonstrate/reproduce the problem. In your example there's lots of missing references and such.

@GreatDanton
Copy link
Author

GreatDanton commented Aug 10, 2023

I hope this is better

package main

import (
	"errors"
	"fmt"
	"github.com/BurntSushi/toml"
	"log"
	"strings"
)

type CustomType uint8

func (n *CustomType) UnmarshalText(text []byte) error {
	t := strings.TrimSpace(string(text))
	switch t {
	case "number_and_text":
		*n = 0
	case "number":
		*n = 1
	case "text":
		*n = 2
	default:
		// TODO: how can I get a line number or the name of a currently decoded field here?
		// I am trying to decode multiple fields of this same type (CustomType), so I
		// need some way to distinguish between them.
		return fmt.Errorf("invalid reference type: available options [%d, %d, %d], but got: %q", 0, 1, 2, t)
	}
	return nil
}

type MyConfig struct {
	Field1 CustomType `toml:"field1"`
	Field2 CustomType `toml:"field2"`
	Field3 CustomType `toml:"field3"`
}

func main() {
	CONFIG := `
	field1 = "number_and_text"
	field2 = "number"
	field3 = "invalid enum"
    `

	config := &MyConfig{}
	md, err := toml.Decode(CONFIG, config)
	if err != nil {
		var pErr toml.ParseError
		if errors.As(err, &pErr) {
			log.Fatalf("toml: config parse error: %v", pErr.ErrorWithUsage())
		}

		// err could not be cast to a toml.ParseError, which means our own unmarshaller
		// returned an error. Here I would need some way to report which field has invalid
                // value (field1, field2 or field3?)
		if false {
			// md contains context with our field that reported a decode error, but 
                        // it's a private member
			fmt.Println(md)
		}
		log.Fatalf("toml: config parse error: %v", err)
	}
}

@arp242
Copy link
Collaborator

arp242 commented Aug 10, 2023

Cheers; that's helpful. I'll have a look tomorrow.

@arp242 arp242 closed this as completed in b6fe702 Oct 1, 2023
@arp242
Copy link
Collaborator

arp242 commented Oct 1, 2023

Sorry, I forgot about your issue.

I fixed it; if you use go get github.com/BurntSushi/toml@master you should automatically get a ParseError, and your code should work.

nrdufour pushed a commit to nrdufour/marmitton that referenced this issue May 24, 2024
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [github.com/BurntSushi/toml](https://github.com/BurntSushi/toml) | require | minor | `v1.3.2` -> `v1.4.0` |

---

### Release Notes

<details>
<summary>BurntSushi/toml (github.com/BurntSushi/toml)</summary>

### [`v1.4.0`](https://github.com/BurntSushi/toml/releases/tag/v1.4.0)

[Compare Source](BurntSushi/toml@v1.3.2...v1.4.0)

This version requires Go 1.18

-   Add toml.Marshal() ([#&#8203;405](BurntSushi/toml#405))

-   Require 2-digit hour ([#&#8203;320](BurntSushi/toml#320))

-   Wrap UnmarshalTOML() and UnmarshalText() return values in ParseError for position information ([#&#8203;398](BurntSushi/toml#398))

-   Fix inline tables with dotted keys inside inline arrays (e.g. `k=[{a.b=1}]`) ([#&#8203;400](BurntSushi/toml#400))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4zNzQuMyIsInVwZGF0ZWRJblZlciI6IjM3LjM3NC4zIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://git.internal/nrdufour/marmitton/pulls/31
Co-authored-by: Renovate <renovate@ptinem.casa>
Co-committed-by: Renovate <renovate@ptinem.casa>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants