You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up from the review of #422. Tool-execution spans set a single flat error.type = "tool_execution_error" on failure (forge-core/runtime/loop.go, tool-call branch). semconv's error.type is meant to be a low-cardinality classification, so operators can group failures by kind ("show me auth failures across all tools"). Refine the single constant into a small, fixed vocabulary.
The full error text is not lost today — it's preserved via toolSpan.RecordError(execErr) + SetStatus(codes.Error, execErr.Error()). This issue is purely about the classification attribute, so it stays additive and low-risk.
Proposed vocabulary
A closed set of low-cardinality values, defaulting to execution_error when nothing more specific is known:
Summary
Follow-up from the review of #422. Tool-execution spans set a single flat
error.type = "tool_execution_error"on failure (forge-core/runtime/loop.go, tool-call branch). semconv'serror.typeis meant to be a low-cardinality classification, so operators can group failures by kind ("show me auth failures across all tools"). Refine the single constant into a small, fixed vocabulary.The full error text is not lost today — it's preserved via
toolSpan.RecordError(execErr)+SetStatus(codes.Error, execErr.Error()). This issue is purely about the classification attribute, so it stays additive and low-risk.Proposed vocabulary
A closed set of low-cardinality values, defaulting to
execution_errorwhen nothing more specific is known:error.typetimeoutcancelledauthnot_foundcli_executeLookPath), 404 from an API/MCP toolinvalid_argsegress_blockedexecution_errorKeep the set closed and documented; unknown →
execution_error(never echo the raw message intoerror.type, which would blow up cardinality).Where to classify
e.tools.ExecutereturnsexecErr. Map it witherrors.Is/errors.Asagainst existing sentinels rather than string matching where possible:context.DeadlineExceeded→timeout;context.Canceled→cancelled(note: the loop already special-cases ctx cancellation upstream — keep consistent).forge-core/security—egress_blockedevents already exist) →egress_blocked.forge-core/mcp→auth/not_found.cli_execute:exec.ErrNotFound/ LookPath failures →not_found; arg-validation rejections →invalid_args.execution_error.A small classifier helper (e.g.
classifyToolError(err) stringinforge-core/runtime) keepsloop.goreadable and unit-testable in isolation.Acceptance criteria
error.typefrom the closed vocabulary above; defaultexecution_error.error.type(cardinality guard); full detail still onRecordError+ span status.classifyToolErrorunit tests cover each mapped category + the default.docs/core-concepts/observability-tracing.mdlists theerror.typevalues.References
forge-core/runtime/loop.go— tool-call branch, currenterror.type = "tool_execution_error"forge-core/observability/attrs.go—AttrErrorTypeforge-core/security(egress deny),forge-core/mcp(transport/auth),cli_execute(LookPath / arg validation)No code changes in this issue — design + backlog.