Skip to content

SD card recording silently fails with write_error at exactly 2GB (2^31-1 bytes) due to missing large-file support #118

Description

@Nicola-polentini1972

Summary

Recordings to SD card (.ts segments) via waybeam (star6e backend, SSC338Q) hard-fail with stop_reason: "write_error" at exactly 2147483647 bytes (2^31-1, i.e. INT32_MAX), regardless of the configured record.maxMB / record.maxSeconds rotation thresholds. This happens well before the configured segment-rotation size is reached (e.g. maxMB: 5000 never gets a chance to trigger), so a single continuous recording simply stops/fails instead of rotating into a new segment.

Repo affected: OpenIPC/waybeam_venc (filed here since Issues are disabled on that repo).

Environment

  • SoC / backend: SigmaStar SSC338Q (star6e backend)
  • OS: Buildroot 2024.02.10, kernel 4.9.84, armv7l (32-bit)
  • Recording filesystem: exFAT (no inherent 4 GB/2 GB limit)
  • waybeam binary build: Jun 13 2026; contract_version reported as 0.10.1
  • record config in /etc/waybeam.json:
    "record": {
      "enabled": false,
      "dir": "/mnt/mmcblk0p1/ruby",
      "format": "ts",
      "mode": "dual",
      "maxSeconds": 1200,
      "maxMB": 5000,
      "bitrate": 40000,
      "fps": 0,
      "gopSize": 1.0
    }

Steps to reproduce

  1. Set record.maxMB above ~2000 (e.g. 5000) and start onboard recording (dual-VENC mode) at a bitrate/fps high enough to reach 2 GB within the desired session length (e.g. 1080p60 @ 25-40 Mbps).
  2. Let the recording run until the written file approaches ~2 GB.
  3. Query GET /api/v1/record/status.

Expected behavior

Per documentation/SD_CARD_RECORDING.md, when a rotation threshold is reached the recorder should: wait for the next IDR boundary, close+fsync the current segment, and open a new .ts file with fresh PAT/PMT. Since maxMB (5000) is well above 2 GB, recording should continue uninterrupted as a single segment past 2 GB.

Actual behavior

The write fails outright:

{"ok":true,"data":{"active":false,"format":"ts","path":"","frames":0,"bytes":0,"segments":0,"stop_reason":"write_error"}}

The last segment file on disk is truncated at exactly 2147483647 bytes. This was reproduced twice independently (two separate recording sessions on the same device both produced files of exactly this byte count), so it is fully deterministic, not a transient I/O glitch.

Root cause (found in source)

In src/star6e_ts_recorder.c, open_new_segment():

state->fd = open(state->path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);

No O_LARGEFILE is passed, and neither this file nor its includes define _FILE_OFFSET_BITS 64 / _LARGEFILE64_SOURCE. On this 32-bit ARM target that leaves off_t as a 32-bit signed type, so the kernel returns EFBIG once the file offset would exceed 2^31-1 -- independent of the filesystem's real limits (exFAT has none here) and independent of the app-level rotation logic.

The rotation check itself (segment_bytes >= max_bytes in the same file, using correctly-sized uint64_t counters) is logically fine, but it only runs against the configured maxMB. When maxMB is set above ~2047 MB (a very reasonable value for a long recording), the OS-level write fails first, before the app's own rotation logic ever gets a chance to close the segment early.

Suggested fix

  • Build with _FILE_OFFSET_BITS=64 (or _LARGEFILE64_SOURCE + open64()) so off_t is 64-bit, removing the artificial 2 GB ceiling entirely, or
  • As a defensive belt-and-suspenders fix, clamp/warn when maxMB (or the default when maxMB: 0) would allow a segment to approach the 32-bit off_t limit on 32-bit targets, and force rotation before 2^31-1 bytes regardless of user config.

Workaround

Setting record.maxMB below ~2000 (e.g. 1900) causes the existing rotation logic to close the segment before hitting the real 2 GB ceiling, avoiding the write_error -- confirmed as a viable workaround on-device, but the underlying 32-bit off_t limitation should still be fixed at the source level since it silently truncates any config with maxMB (or 0 = unlimited) above ~2 GB.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions