Skip to content

Frame Polling Fails With "URI is not absolute"

Metadata

  • Date: 2026-04-03
  • Status: fixed
  • Severity: high
  • Related issue/ticket: N/A
  • Owner: N/A

About

Overview: - During capture, frame polling logged frame_poll_error with java.lang.IllegalArgumentException: URI is not absolute. - This is important because frame discovery fails, so JPEG frames are never enqueued for upload and session visual data is effectively not saved to the backend.

Technical Questions: - Assumption validated: native startRecordingFrames()/stopRecordingFrames() return filesystem paths (for example /tmp/... or /data/...) without a URI scheme. - Bug age appears recent to current frame-polling implementation that switched to expo-file-system Directory. - Obvious miss: Directory/File were constructed with raw paths rather than absolute URIs. - Required state: SDK/device path (not stub mode), active frame recording, and polling/final-poll execution.

Resources: - Runtime error signal: main/app/lib/capture-session.ts (frame_poll_error, frame_final_poll_error). - Native return values: - main/app/wearables-module/android/src/main/java/expo/modules/wearablesmodule/WearablesModule.kt - main/app/wearables-module/ios/WearablesModule.swift - Fix and regression coverage: - main/app/lib/capture-session.ts - main/app/__tests__/capture-session.test.ts

Steps to cause failure

flowchart LR
StartCapture --> NativeReturnsPath["Native returns /tmp/... (no scheme)"]
NativeReturnsPath --> Poll["JS new Directory(path).list()"]
Poll --> Throws["URI is not absolute"]
Throws --> FramePollError["frame_poll_error logged"]
FramePollError --> NoUpload["No new frames enqueued/uploaded"]

System

flowchart TD
Native[Wearables native module writes JPEGs to temp dir] --> JS[Capture session polling]
JS --> FS[expo-file-system Directory/File]
JS --> Queue[FrameUploadQueue]
Queue --> API[POST /sessions/:id/frames]

Notes about the system can go here.

Reproduction Details

  1. Ensure capture runs with SDK available so native startRecordingFrames() is used.
  2. Return a bare absolute path (for example /tmp/frames_123) from native frame-directory methods.
  3. Polling attempts new Directory(path).list() and throws URI is not absolute; no frames are queued.

Reproduction test (unit preferred): npm test -- capture-session.test.ts --runInBand

Notes for PR

Root cause is path/URI contract mismatch between native frame directory outputs and expo-file-system URI expectations.
Fix normalizes all native/local paths to absolute URIs (file://...) before creating Directory and File objects in capture session code.
Regression test validates polling and final polling no longer hit URI-absolute errors for native path-style returns.

Audit Log

ID Action Note Context
1 Create audit log Initialized investigation and dedupe check in docs/bugs issue created
2 Inspect logs/code Traced runtime error to capture-session frame polling and native path returns root-cause analysis
3 Add regression test Added test that enforces file:// URI normalization in polling/final polling path reproduction harness
4 Fix root cause Added toAbsoluteUri() normalization before Directory/File usage code fix
5 Verify Ran npm test -- capture-session.test.ts --runInBand and confirmed pass post-fix validation
6 Code-review gate Reviewed diff for scope, DRY/YAGNI, and test coverage of fix path final check

Verification

  • [x] Reproduced failure before fix
  • [x] Reproduction test fails before fix
  • [x] Root cause identified with evidence
  • [x] Fix applied at source (no workaround-only patch)
  • [x] Reproduction test passes after fix
  • [x] Reproduction path now passes
  • [x] Regression test added/updated (or N/A with reason)
  • [x] Verified no duplicate solved-bug log exists for same root cause