{"record":{"id":"02948a19d919fda9","repo":"signalapp/Signal-Server","slug":"start-timestamp-not-specified","errorCode":null,"errorMessage":"Start timestamp not specified","messagePattern":"Start timestamp not specified","errorType":"validation","errorClass":"CallQualityInvalidArgumentsException","httpStatus":null,"severity":"warning","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/metrics/CallQualitySurveyManager.java","lineNumber":161,"sourceCode":"    }\n\n    GoogleApiUtil.toCompletableFuture(pubSubPublisher.publish(PubsubMessage.newBuilder()\n            .setData(pubSubMessageBuilder.build().toByteString())\n            .build()), pubSubCallbackExecutor)\n        .whenComplete((_, throwable) -> {\n          if (throwable != null) {\n            logger.warn(\"Failed to publish call quality survey pub/sub message\", throwable);\n          }\n\n          Metrics.counter(PUB_SUB_MESSAGE_COUNTER_NAME, \"success\", String.valueOf(throwable == null))\n              .increment();\n        });\n  }\n\n  @VisibleForTesting\n  static void validateRequest(final SubmitCallQualitySurveyRequest request) throws CallQualityInvalidArgumentsException {\n    if (request.getStartTimestamp() == 0) {\n      throw new CallQualityInvalidArgumentsException(\"Start timestamp not specified\", \"startTimestamp\");\n    }\n\n    if (request.getEndTimestamp() == 0) {\n      throw new CallQualityInvalidArgumentsException(\"End timestamp not specified\", \"endTimestamp\");\n    }\n\n    if (StringUtils.isBlank(request.getCallType())) {\n      throw new CallQualityInvalidArgumentsException(\"Call type not specified\", \"callType\");\n    }\n\n    if (StringUtils.isBlank(request.getCallEndReason())) {\n      throw new CallQualityInvalidArgumentsException(\"Call end reason not specified\", \"callEndReason\");\n    }\n  }\n}\n","sourceCodeStart":143,"sourceCodeEnd":177,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/metrics/CallQualitySurveyManager.java#L143-L177","documentation":"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.","triggerScenarios":"POSTing to the call-quality survey endpoint via submitCallQualitySurvey with a SubmitCallQualitySurveyRequest JSON body that omits startTimestamp or explicitly sets it to 0.","commonSituations":"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.","solutions":["Set startTimestamp (epoch seconds/millis per API contract) in the SubmitCallQualitySurveyRequest before submitting","On the client, capture and persist the call start time when the call is initiated, not at survey time","Verify the JSON field is named startTimestamp exactly so Jackson populates it instead of leaving it 0"],"exampleFix":"// before\n{\"callType\": \"audio\", \"endTimestamp\": 1700000000}\n// after\n{\"startTimestamp\": 1699999400, \"callType\": \"audio\", \"endTimestamp\": 1700000000}","handlingStrategy":"validation","validationCode":"if (!request.startTimestamp || request.startTimestamp === 0) { throw new Error('startTimestamp is required before submitting a call quality survey'); }","typeGuard":"const hasStartTimestamp = (r) => typeof r.startTimestamp === 'number' && r.startTimestamp > 0;","tryCatchPattern":"try { await submitCallQualitySurvey(request); } catch (CallQualityInvalidArgumentsException e) { if ('startTimestamp'.equals(e.getField())) { recoverStartTimestampAndResubmit(); } }","preventionTips":["Record the call start time at call initiation, not at survey submission","Validate all required survey fields client-side before the HTTP request","Use non-zero sentinels for unknown timestamps and fail fast in client code"],"tags":["api","validation","missing-field"],"backgroundTag":"missing-required-argument","analyzedSha":"100ab61c82627582c867d19e1c0561ba2781e927","analyzedAt":"2026-09-09T13:29:47.883Z","contentChangedAt":"2026-09-09T13:29:47.883Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}