Skip to content

Commit 58c4ec5

Browse files
authored
Truncate long errors keeping head and diagnostic tail (#263)
* Truncate long errors keeping the diagnostic tail Drop the first 40% of long error messages (>80 chars) since the useful diagnostic info (e.g. PCR mismatches) sits at the end, after layers of generic wrapping. * Truncate long errors keeping head and diagnostic tail For errors >120 chars, show the beginning + "..." + last 40%. Nested error wrapping puts the useful diagnostic (e.g. PCR mismatches) at the end; this keeps both ends visible.
1 parent 1c4121f commit 58c4ec5

2 files changed

Lines changed: 44 additions & 1 deletion

File tree

cmd/workflow/logs/logs.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,12 @@ func (h *handler) printErrors(ctx context.Context, client *graphqlclient.Client,
289289
if ev.Status == "failure" && len(ev.Errors) > 0 {
290290
errMsg := ev.Errors[0].Error
291291
if len(errMsg) > 120 {
292-
errMsg = errMsg[:120] + "..."
292+
tail := errMsg[len(errMsg)-len(errMsg)*2/5:] // last 40%
293+
head := 120 - len(tail) - 3
294+
if head < 0 {
295+
head = 0
296+
}
297+
errMsg = errMsg[:head] + "..." + tail
293298
}
294299
fmt.Printf(" -> %s: %s\n", ev.CapabilityID, errMsg)
295300
}

cmd/workflow/logs/logs_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,44 @@ func TestExecute(t *testing.T) {
180180
assert.Greater(t, failureIdx, successIdx, "oldest execution should appear first")
181181
})
182182

183+
t.Run("long error is truncated keeping tail", func(t *testing.T) {
184+
longErr := "failed to execute enclave request. enclave ID: abc123, error: attestation validation failed for ExecuteBatch: expected PCR0 deadbeef, got cafebabe"
185+
ts := newMockGraphQL(t, mockConfig{
186+
workflows: []map[string]any{
187+
{"uuid": "wf-1", "name": "test-workflow", "status": "ACTIVE"},
188+
},
189+
executions: []map[string]any{
190+
{
191+
"uuid": "exec-1",
192+
"status": "FAILURE",
193+
"startedAt": "2026-02-12T16:00:00Z",
194+
"finishedAt": "2026-02-12T16:00:01Z",
195+
},
196+
},
197+
events: []map[string]any{
198+
{
199+
"capabilityID": "confidential-http@1.0.0",
200+
"status": "failure",
201+
"errors": []map[string]any{{"error": longErr, "count": 1}},
202+
},
203+
},
204+
})
205+
defer ts.Close()
206+
207+
output := captureStdout(t, func() {
208+
h := newTestHandler(ts.URL, "test-workflow", false, 10)
209+
err := h.Execute(context.Background())
210+
require.NoError(t, err)
211+
})
212+
213+
// Head (beginning) should be present
214+
assert.Contains(t, output, "failed to execute enclave")
215+
// Tail (last 40%) should survive truncation
216+
assert.Contains(t, output, "expected PCR0 deadbeef, got cafebabe")
217+
// Middle should be elided
218+
assert.Contains(t, output, "...")
219+
})
220+
183221
t.Run("workflow not found", func(t *testing.T) {
184222
ts := newMockGraphQL(t, mockConfig{})
185223
defer ts.Close()

0 commit comments

Comments
 (0)