Files
larksuite-cli/shortcuts/calendar/errors.go
evandance f3949f04c4 feat(calendar): emit typed error envelopes across the calendar domain (#1232)
Calendar commands now return structured, typed error envelopes for every
failure mode — input validation, internal faults, and API responses —
instead of legacy generic errors. Callers and AI agents get consistent
exit codes and a machine-readable shape (type / subtype / code / hint),
and can tell bad input, an internal fault, and an API rejection apart.
Validation errors are attributed to the offending flag.

Server-supplied error details (e.g. why an event time was rejected) are
surfaced on the typed error's hint via a shared classifier improvement
that benefits every domain. Multi-step operations (create-with-attendees
rollback, multi-field update) preserve the real failure's classification
and report which steps completed.

The whole calendar domain is now lint-locked against reintroducing legacy
error constructors.
2026-06-05 13:06:50 +08:00

45 lines
1.3 KiB
Go

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package calendar
import (
"errors"
"fmt"
"strings"
"github.com/larksuite/cli/errs"
)
// withStepContext annotates err with multi-step context (e.g. which steps
// already completed, or that a rollback ran) while preserving the underlying
// failure's classification. An already-typed error keeps its own
// category/subtype/code/log_id; we only append the formatted context to its
// Hint so the top-level envelope still tells the truth about what failed.
// Only an unclassified error falls back to a typed internal wrap.
func withStepContext(err error, format string, args ...any) error {
if err == nil {
return nil
}
extra := fmt.Sprintf(format, args...)
if p, ok := errs.ProblemOf(err); ok {
if strings.TrimSpace(p.Hint) != "" {
p.Hint = p.Hint + "\n" + extra
} else {
p.Hint = extra
}
return err
}
return errs.NewInternalError(errs.SubtypeSDKError, "%s", err.Error()).WithHint(extra).WithCause(err)
}
// withParam attaches the offending flag to a typed validation error, preserving
// the original error instead of re-wrapping it. Non-validation errors pass through.
func withParam(err error, flag string) error {
var ve *errs.ValidationError
if errors.As(err, &ve) {
return ve.WithParam(flag)
}
return err
}