Skip to content

apis.errs.Also does not propagate error level #2514

Open

Description

@lbernick

/area API
/kind bug

Steps to Reproduce the Problem

Using "warning" level error introduced in #2498:

func TestFoo(t *testing.T) {
	var errs *apis.FieldError
	errs = errs.Also(apis.FieldError("foo").At(apis.WarningLevel))
	if errs.Level != apis.WarningLevel {
		t.Errorf("Expected an error at warning level but got level %s", errs.Level)
	}
}

Expected Behavior

The aggregated error has the level that is the highest level of any errors combined with Also.
In the example above, I would expect errs.Level to be Warning, and errs.Filter(apis.WarningLevel).Level to also be Warning.

Actual Behavior

In the example above, errs.Level and errs.Filter(apis.WarningLevel).Level are both Error. (i.e. an error at level "warning" aggregated with no error turns into an error at level "error")

@mattmoor

Activity

  1. mattmoor commented on May 5, 2022

    @mattmoor
    Contributor

    Thanks for opening this 🙏

    cc @dprotaso @evankanderson @vaikas @n3wscott

    To reiterate some of the thread in Tekton, this is sort of a reflection of the awkward conflation of apis.FieldError as both an error and an aggregation of errors (via .Also())

    In your example, errs.Message won't match the single error it contains either, so I think the breakdown here is more general than the new Level field. I wonder if for aggregated errors we should set Level to reflect the constituents and perhaps add a Mixed level when multiple levels are present? This would at least make the cases @lbernick describes a bit more intuitive. I'd guess it would avoid back-compat problems since nothing is really using anything but error yet, so nothing should get a mixed level with .Also.

    What do folks think?

  2. vaikas commented on May 5, 2022

    @vaikas
    Contributor

    @mattmoor you have a link to Tekton thread handy since it seems to have more context?

  3. mattmoor commented on May 5, 2022

    @mattmoor
    Contributor
  4. evankanderson commented on May 5, 2022

    @evankanderson
    Member

    I'd expect the "lowest" level when aggregating via Also (since ErrorLevel is 0 and counts upward), but otherwise I agree with the diagnosis.

    Given that this code is unlikely to be in a tight loop, I wonder if looping over the set of contained errors to determine the correct collection-level would be correct. You could early-exit the loop if ErrorLevel is encountered, since that's the lowest level. If we imagine a Suggestion level that's less severe than Warning:

    Err1 Err2 Alsoed (symmetrical)
    error error error
    error warning error
    error suggestion error
    warning warning warning
    warning suggestion warning
    suggestion suggestion suggestion

    The worst case performance would be constructing a long chain of Warning level errors, where you'd end up scanning O(n^2) errors as you add one to the head of the chain, but this is probably acceptable (and maybe we'd cache things so it's actually O(n), I haven't thought too deeply).

  5. github-actions commented on Aug 4, 2022

    @github-actions
    Contributor

    This issue is stale because it has been open for 90 days with no
    activity. It will automatically close after 30 more days of
    inactivity. Reopen the issue with /reopen. Mark the issue as
    fresh by adding the comment /remove-lifecycle stale.

  6. added
    lifecycle/staleDenotes an issue or PR has remained open with no activity and has become stale.
    on Aug 4, 2022
  7. dprotaso commented on Aug 5, 2022

    @dprotaso
    Member

    /lifecycle frozen

  8. added
    lifecycle/frozenIndicates that an issue or PR should not be auto-closed due to staleness.
    and removed
    lifecycle/staleDenotes an issue or PR has remained open with no activity and has become stale.
    on Aug 5, 2022
  9. JeromeJu commented on Sep 14, 2022

    @JeromeJu

    Thanks @evankanderson for the table of the combinations of errs incurred.

    I would like to confirm my understanding on the O(n) solution, would that need to introduce a hash-table in a (possible cyclic?) graph?

  10. evankanderson commented on Sep 15, 2022

    @evankanderson
    Member

    You shouldn't need a hash table for caching, as you only need to track the "head" of the chain as long as the cache is correct. Using .Also() in any sort of correct issue should produce a tree, not an arbitrary graph.

    If you want, you could use the go benchmark library to compare approaches if you want to learn that...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area/APIkind/bugCategorizes issue or PR as related to a bug.lifecycle/frozenIndicates that an issue or PR should not be auto-closed due to staleness.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions