signalapp/Signal-Server · warning · CallQualityInvalidArgumentsException

Start timestamp not specified

Error message

Start timestamp not specified

What it means

validateRequest in CallQualitySurveyManager rejects a call-quality survey submission whose startTimestamp is 0, meaning the client never supplied a call start time. The exception carries the offending field name (startTimestamp) and is surfaced to the client as an invalid-arguments API error rather than a server fault. This guard exists because survey records without a start time cannot be evaluated.

Solutions

  1. Set startTimestamp (epoch seconds/millis per API contract) in the SubmitCallQualitySurveyRequest before submitting
  2. On the client, capture and persist the call start time when the call is initiated, not at survey time
  3. Verify the JSON field is named startTimestamp exactly so Jackson populates it instead of leaving it 0

Example fix

// before
{"callType": "audio", "endTimestamp": 1700000000}
// after
{"startTimestamp": 1699999400, "callType": "audio", "endTimestamp": 1700000000}
Defensive patterns

Strategy: validation

Validate before calling

if (!request.startTimestamp || request.startTimestamp === 0) { throw new Error('startTimestamp is required before submitting a call quality survey'); }

Type guard

const hasStartTimestamp = (r) => typeof r.startTimestamp === 'number' && r.startTimestamp > 0;

Try / catch

try { await submitCallQualitySurvey(request); } catch (CallQualityInvalidArgumentsException e) { if ('startTimestamp'.equals(e.getField())) { recoverStartTimestampAndResubmit(); } }

Prevention

When it happens

Trigger: POSTing to the call-quality survey endpoint via submitCallQualitySurvey with a SubmitCallQualitySurveyRequest JSON body that omits startTimestamp or explicitly sets it to 0.

Common situations: Older or buggy clients that fail to record call start time; hand-written test requests missing the field; JSON deserialization leaving the long at its default 0 value because the field was renamed or absent.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of signalapp/Signal-Server@100ab61c82 (2026-09-09). Data as JSON: /api/errors/02948a19d919fda9. Report an issue: GitHub.

Appendix: source

Thrown at service/src/main/java/org/whispersystems/textsecuregcm/metrics/CallQualitySurveyManager.java:161

    }

    GoogleApiUtil.toCompletableFuture(pubSubPublisher.publish(PubsubMessage.newBuilder()
            .setData(pubSubMessageBuilder.build().toByteString())
            .build()), pubSubCallbackExecutor)
        .whenComplete((_, throwable) -> {
          if (throwable != null) {
            logger.warn("Failed to publish call quality survey pub/sub message", throwable);
          }

          Metrics.counter(PUB_SUB_MESSAGE_COUNTER_NAME, "success", String.valueOf(throwable == null))
              .increment();
        });
  }

  @VisibleForTesting
  static void validateRequest(final SubmitCallQualitySurveyRequest request) throws CallQualityInvalidArgumentsException {
    if (request.getStartTimestamp() == 0) {
      throw new CallQualityInvalidArgumentsException("Start timestamp not specified", "startTimestamp");
    }

    if (request.getEndTimestamp() == 0) {
      throw new CallQualityInvalidArgumentsException("End timestamp not specified", "endTimestamp");
    }

    if (StringUtils.isBlank(request.getCallType())) {
      throw new CallQualityInvalidArgumentsException("Call type not specified", "callType");
    }

    if (StringUtils.isBlank(request.getCallEndReason())) {
      throw new CallQualityInvalidArgumentsException("Call end reason not specified", "callEndReason");
    }
  }
}

View on GitHub (pinned to 100ab61c82)