Error Handling
Relevant source files
The following files were used as context for generating this wiki page:
The Heyme application employs a multi-layered error handling strategy that combines client-side validation, server-side API checks, and third-party monitoring services. This approach ensures a robust user experience by catching errors early on the client, validating data on the server, and providing developers with insights into runtime exceptions through session replay and error tracking.
The primary tool for server-side error monitoring is Highlight.run, which is integrated into the Next.js application to wrap API endpoints. On the client-side, particularly on the recording page, extensive state management is used to handle user input errors, media device permission issues, and video upload failures, providing clear feedback to the user.
Server-Side Error Monitoring with Highlight.run
The project integrates with Highlight.run, a monitoring and session replay tool, to capture and analyze errors occurring within the Next.js API routes. This is facilitated by the @highlight-run/next package.
Sources: package.json:10, pages/_app.tsx:5,15, pages/api/store.ts:3,26, pages/api/dispatch.ts:8,103
Initialization
Highlight is initialized in the main application component, _app.tsx. This ensures that the monitoring service is active for the entire application lifecycle. The project's unique ID is used to associate the application with the correct Highlight.run project.
// pages/_app.tsx:15
H.init('4d7zk0eo')
Sources: pages/_app.tsx:15
API Endpoint Wrapping
API handlers are wrapped with the withHighlight higher-order component (HOC). This HOC intercepts requests and responses, allowing Highlight.run to capture errors, logs, and other session details automatically. This is applied to both the /api/store and /api/dispatch endpoints.
The diagram below illustrates how an API request is processed through the withHighlight wrapper.
This diagram shows the flow of an API request being processed by the withHighlight HOC, which captures any errors that occur during the handler's execution.
Sources: pages/api/store.ts:26, pages/api/dispatch.ts:103
API Endpoint Error Handling
Beyond automated monitoring, API endpoints include explicit validation logic to handle incorrect or incomplete client requests gracefully.
/api/store Input Validation
The handleStoreVideo function in /api/store.ts performs validation to ensure all required data fields are present in the request body. If any of the required fields are missing, it immediately returns a 400 Bad Request status with an informative JSON message, preventing further processing with invalid data.
// pages/api/store.ts:10-17
if (
!data.video_url ||
!data.email ||
!data.send_at ||
!data.send_to ||
!data.created_at
) {
return response.status(400).json({ message: "Invalid data provided." })
}
The following flowchart details the logic within the /api/store endpoint.
This flowchart shows the validation and processing logic for storing a new video record.
Sources: pages/api/store.ts:10-17
Client-Side Error Handling (/recording page)
The /recording page contains the most complex error handling logic, as it deals with direct user interaction, browser APIs, and file uploads. Errors are managed using React state to provide immediate and contextual feedback to the user.
Sources: pages/recording.tsx
Media Permissions & Compatibility
The application must access the user's camera and microphone. The accessUserDevices function is wrapped in a try...catch block to handle potential errors, such as the user denying permission (NotAllowedError) or the browser not supporting WebRTC.
| State Variable | Purpose |
|---|---|
hasPermissionIssues | Set to true if the user denies media permissions. Triggers a UI message asking the user to check their browser settings. |
isWebRTCSupported | Set to false if getUserMedia fails for reasons other than permission denial. Triggers a warning and suggests uploading a file instead. |
Sources: pages/recording.tsx:37, 50, 203-217
The logic for accessing user devices is as follows:
This diagram shows the process of requesting media device access and handling the possible success and failure outcomes.
Sources: pages/recording.tsx:203-228
Form Input Validation
The recording page includes a form for the user to specify the recipient's email and the delivery date. Validation is performed on blur for these fields.
| Field | State Variable | Validation Logic | Error Message |
|---|---|---|---|
error | Checks if the field is empty or if the value does not match a standard email regex. | "Email required" or "Invalid email" | |
| Deliver In | dateError | Checks if the field is empty or if the selected date is in the past. | "Date required" or "Please select a date in the future" |
The disabled attribute of the final "Upload" button is tied to these error states, preventing submission of an invalid form.
Sources: pages/recording.tsx:43, 46, 298-319, 520
Video Upload Errors
Error handling is implemented for both recording and file uploading scenarios.
-
Uploaded Video Duration: When a user uploads a video file, a
loadedmetadataevent listener checks the video's duration. If it exceeds the 5-minute limit (300 seconds), theuploadErrorstate is set, and the user is notified.
Sources: pages/recording.tsx:415-425 -
Cloudinary Upload Failure: The
uploadVideoToCloudinaryfunction is called within atry...catchblock. If the Axios request to Cloudinary fails, theuploadToCloudinaryErrorstate is set, the progress bar is reset, and a failure message is displayed.
Sources: pages/recording.tsx:112-116, 126-130
This sequence diagram shows the video upload process and its failure points.
This diagram illustrates the sequence of events during video upload, highlighting the error path if the Cloudinary upload fails.
Server-Side Rendering (SSR) Edge Cases
The application handles cases where data is not found during server-side rendering. In the watch/[id] page, if fetchVideoById returns null (meaning the video ID is not in the database), getServerSideProps returns an object with notFound: true. This instructs Next.js to render a standard 404 page.
This behavior is confirmed by a unit test in tests/api/watch.spec.tsx.
// tests/api/watch.spec.tsx:59-68
test('returns notFound: true if video is not found from getServerSideProps', async () => {
createMysqlConnectionMock.mockReturnValue({})
fetchVideoByIdMock.mockResolvedValue(null)
const context = {
params: { id: FAKE_VIDEO_ID },
} as unknown as GetServerSidePropsContext
const result = await getServerSideProps(context)
expect(fetchVideoById).toHaveBeenCalledWith({}, FAKE_VIDEO_ID)
expect(result).toEqual({ notFound: true })
})
Sources: tests/api/watch.spec.tsx:59-68