Standardize and enhance error handling across hooks and worker service (#295)

* Enhance error logging in hooks

- Added detailed error logging in context-hook, new-hook, save-hook, and summary-hook to capture status, project, port, and relevant session information on failures.
- Improved error messages thrown in save-hook and summary-hook to include specific context about the failure.

* Refactor migration logging to use console.log instead of console.error

- Updated SessionSearch and SessionStore classes to replace console.error with console.log for migration-related messages.
- Added notes in the documentation to clarify the use of console.log for migration messages due to the unavailability of the structured logger during constructor execution.

* Refactor SDKAgent and silent-debug utility to simplify error handling

- Updated SDKAgent to use direct defaults instead of happy_path_error__with_fallback for non-critical fields such as last_user_message, last_assistant_message, title, filesRead, filesModified, concepts, and summary.request.
- Enhanced silent-debug documentation to clarify appropriate use cases for happy_path_error__with_fallback, emphasizing its role in handling unexpected null/undefined values while discouraging its use for nullable fields with valid defaults.

* fix: correct happy_path_error__with_fallback usage to prevent false errors

Fixes false "Missing cwd" and "Missing transcript_path" errors that were
flooding silent.log even when values were present.

Root cause: happy_path_error__with_fallback was being called unconditionally
instead of only when the value was actually missing.

Pattern changed from:
  value: happy_path_error__with_fallback('Missing', {}, value || '')

To correct usage:
  value: value || happy_path_error__with_fallback('Missing', {}, '')

Fixed in:
- src/hooks/save-hook.ts (PostToolUse hook)
- src/hooks/summary-hook.ts (Stop hook)
- src/services/worker/http/routes/SessionRoutes.ts (2 instances)

Impact: Eliminates false error noise, making actual errors visible.

Addresses issue #260 - users were seeing "Missing cwd" errors despite
Claude Code correctly passing all required fields.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Enhance error logging and handling across services

- Improved error messages in SessionStore to include project context when fetching boundary observations and timestamps.
- Updated ChromaSync error handling to provide more informative messages regarding client initialization failures, including the project context.
- Enhanced error logging in WorkerService to include the package path when reading version fails.
- Added detailed error logging in worker-utils to capture expected and running versions during health checks.
- Extended WorkerErrorMessageOptions to include actualError for more informative restart instructions.

* Refactor error handling in hooks to use standardized fetch error handler

- Introduced a new error handler `handleFetchError` in `shared/error-handler.ts` to standardize logging and user-facing error messages for fetch failures across hooks.
- Updated `context-hook.ts`, `new-hook.ts`, `save-hook.ts`, and `summary-hook.ts` to utilize the new error handler, improving consistency and maintainability.
- Removed redundant imports and error handling logic related to worker restart instructions from the hooks.

* feat: add comprehensive error handling tests for hooks and ChromaSync client

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Alex Newman
2025-12-13 23:25:43 -05:00
committed by GitHub
parent d42ab1298c
commit 52d2f72a82
27 changed files with 1434 additions and 199 deletions
+9 -17
View File
@@ -233,16 +233,8 @@ export class SDKAgent {
sdk_session_id: session.sdkSessionId,
project: session.project,
user_prompt: session.userPrompt,
last_user_message: happy_path_error__with_fallback(
'Missing last_user_message for summary in SDKAgent',
{ sessionDbId: session.sessionDbId, sdkSessionId: session.sdkSessionId },
message.last_user_message || ''
),
last_assistant_message: happy_path_error__with_fallback(
'Missing last_assistant_message for summary in SDKAgent',
{ sessionDbId: session.sessionDbId, sdkSessionId: session.sdkSessionId },
message.last_assistant_message || ''
)
last_user_message: message.last_user_message || '',
last_assistant_message: message.last_assistant_message || ''
})
},
session_id: session.claudeSessionId,
@@ -276,16 +268,16 @@ export class SDKAgent {
sessionId: session.sessionDbId,
obsId,
type: obs.type,
title: obs.title || happy_path_error__with_fallback('obs.title is null', { obsId, type: obs.type }, '(untitled)'),
filesRead: obs.files_read?.length ?? (happy_path_error__with_fallback('obs.files_read is null/undefined', { obsId }), 0),
filesModified: obs.files_modified?.length ?? (happy_path_error__with_fallback('obs.files_modified is null/undefined', { obsId }), 0),
concepts: obs.concepts?.length ?? (happy_path_error__with_fallback('obs.concepts is null/undefined', { obsId }), 0)
title: obs.title || '(untitled)',
filesRead: obs.files_read?.length ?? 0,
filesModified: obs.files_modified?.length ?? 0,
concepts: obs.concepts?.length ?? 0
});
// Sync to Chroma with error logging
const chromaStart = Date.now();
const obsType = obs.type;
const obsTitle = obs.title || happy_path_error__with_fallback('obs.title is null for Chroma sync', { obsId, type: obs.type }, '(untitled)');
const obsTitle = obs.title || '(untitled)';
this.dbManager.getChromaSync().syncObservation(
obsId,
session.claudeSessionId,
@@ -353,14 +345,14 @@ export class SDKAgent {
logger.info('SDK', 'Summary saved', {
sessionId: session.sessionDbId,
summaryId,
request: summary.request || happy_path_error__with_fallback('summary.request is null', { summaryId }, '(no request)'),
request: summary.request || '(no request)',
hasCompleted: !!summary.completed,
hasNextSteps: !!summary.next_steps
});
// Sync to Chroma with error logging
const chromaStart = Date.now();
const summaryRequest = summary.request || happy_path_error__with_fallback('summary.request is null for Chroma sync', { summaryId }, '(no request)');
const summaryRequest = summary.request || '(no request)';
this.dbManager.getChromaSync().syncSummary(
summaryId,
session.claudeSessionId,
@@ -342,10 +342,10 @@ export class SessionRoutes extends BaseRouteHandler {
tool_input: cleanedToolInput,
tool_response: cleanedToolResponse,
prompt_number: promptNumber,
cwd: happy_path_error__with_fallback(
cwd: cwd || happy_path_error__with_fallback(
'Missing cwd when queueing observation in SessionRoutes',
{ sessionDbId, tool_name },
cwd || ''
''
)
});
@@ -394,10 +394,10 @@ export class SessionRoutes extends BaseRouteHandler {
// Queue summarize
this.sessionManager.queueSummarize(
sessionDbId,
happy_path_error__with_fallback(
last_user_message || happy_path_error__with_fallback(
'Missing last_user_message when queueing summary in SessionRoutes',
{ sessionDbId },
last_user_message || ''
''
),
last_assistant_message
);