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

Allow to get source position of unmarshal errors (enhanced version) #901

Open
wants to merge 5 commits into
base: v3
Choose a base branch
from

Conversation

andig
Copy link

@andig andig commented Sep 18, 2022

Fix #759

Enhanced version of #760. Added capability is that terminal errors, i.e. errors where the parser fails, can also record their source position.

This introduces a second type of errors. We could check if it would be helpful to create a SourceLocator interface for abstracting the ability to retrieve the line number. Didn't think that's worth the additional code since handling the potential slice of UnmarshalErrors requires type checking anyways.

@andig
Copy link
Author

andig commented Sep 19, 2022

I'll look into adding a test for terminal error with line number.

Copy link

@lovromazgon lovromazgon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change seems very useful and even necessary to be able to get more control over errors 👏 I added a suggestion for an addition, which would solve my problem - I need to warn the user if the file contains unknown fields, but continue processing the file if it's the only thing that's wrong.

Comment on lines +334 to 338
type UnmarshalError struct {
Message string
Line int
Column int
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest adding a way to differentiate what type of error actually happened, because not all errors have the same severity. For instance, an error because the file contains an unknown field may only constitute printing a warning, while not being able to unmarshal a known field would probably be reason enough to stop processing the file altogether.

I added a snippet of one possible solution that could plug into the current code. Another would be to create separate Go types for each error, although that would be a bigger change.

Suggested change
type UnmarshalError struct {
Message string
Line int
Column int
}
type UnmarshalError struct {
Type UnmarshalErrorType
Message string
Line int
Column int
}
type UnmarshalErrorType int
const (
UnknownField UnmarshalErrorType = iota
CannotUnmarshal UnmarshalErrorType
// ...
)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would propose to do this in a separate PR as you'll also need to touch the places where these types are generated?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First a disclaimer: I'm not a maintainer of this project, so you don't get the wrong idea, my comments don't have a lot of weight 🙂

The type would only have to be added to the lines where UnmarshalError is created, so all the lines that would need to change are already touched in this PR. That said, a separate PR sounds reasonable to me! I might create it and base it on your PR since I need the functionality in my project.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had something like this in mind: lovromazgon@456dd73

It changes UnmarshalError to an interface and creates specific types for each error. This allows you to know exactly what error happened and act accordingly.

I won't create a PR until @niemeyer responds to this PR though, to not create more noise and confusion.

@andig
Copy link
Author

andig commented Dec 1, 2022

@niemeyer could we kindly ask for a review?

@WGH-
Copy link

WGH- commented Feb 1, 2023

Maybe it would make sense to wrap errors from custom UnmarshalYAML roughly like this, too?

diff --git a/decode.go b/decode.go
index b680695..d96a5c4 100644
--- a/decode.go
+++ b/decode.go
@@ -363,7 +363,7 @@ func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) {
                return false
        }
        if err != nil {
-               fail(err)
+               fail(fmt.Errorf("custom unmarshal failed on line %d column %d: %w", n.Line, n.Column, err))
        }
        return true
 }
@@ -385,7 +385,7 @@ func (d *decoder) callObsoleteUnmarshaler(n *Node, u obsoleteUnmarshaler) (good
                return false
        }
        if err != nil {
-               fail(err)
+               fail(fmt.Errorf("custom unmarshal failed on line %d column %d: %w", n.Line, n.Column, err))
        }
        return true
 }

(I say "roughly" because this way errors might be wrapped multiple times, and we're only interested in the innermost one: custom unmarshal failed on line 1 column 1: custom unmarshal failed on line 111124 column 5: custom unmarshal failed on line 111554 column 13: custom unmarshal failed on line 111555 column 15: custom unmarshal failed on line 111560 column 22)

@andig
Copy link
Author

andig commented May 30, 2023

Friendly ping @niemeyer- it has been half a year now ;)

@lyda
Copy link

lyda commented Oct 9, 2023

I like this idea better than mine in #995. Still, it would be nice if something was picked.

@andig
Copy link
Author

andig commented Apr 20, 2024

ping @niemeyer another year has passed.

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

Successfully merging this pull request may close these issues.

Feature request: Unmarshal error with source position
5 participants