{"record":{"id":"febabac14be4b81b","repo":"nextcloud/server","slug":"x-oc-mtime-header-must-be-a-valid-positive-unix-ti","errorCode":null,"errorMessage":"X-OC-MTime header must be a valid positive unix timestamp greater than one day, got \"%s\".","messagePattern":"X-OC-MTime header must be a valid positive unix timestamp greater than one day, got \"(.+?)\"\\.","errorType":"validation","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"warning","filePath":"apps/dav/lib/Connector/Sabre/MtimeSanitizer.php","lineNumber":29,"sourceCode":"\nclass MtimeSanitizer {\n\tpublic static function sanitizeMtime(string $mtimeFromRequest): int {\n\t\t// In PHP 5.X \"is_numeric\" returns true for strings in hexadecimal\n\t\t// notation. This is no longer the case in PHP 7.X, so this check\n\t\t// ensures that strings with hexadecimal notations fail too in PHP 5.X.\n\t\t$isHexadecimal = preg_match('/^\\s*0[xX]/', $mtimeFromRequest);\n\t\tif ($isHexadecimal || !is_numeric($mtimeFromRequest)) {\n\t\t\tthrow new \\InvalidArgumentException(\n\t\t\t\tsprintf(\n\t\t\t\t\t'X-OC-MTime header must be a valid integer (unix timestamp), got \"%s\".',\n\t\t\t\t\t$mtimeFromRequest\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\t// Prevent writing invalid mtime (timezone-proof)\n\t\tif ((int)$mtimeFromRequest <= 24 * 60 * 60) {\n\t\t\tthrow new \\InvalidArgumentException(\n\t\t\t\tsprintf(\n\t\t\t\t\t'X-OC-MTime header must be a valid positive unix timestamp greater than one day, got \"%s\".',\n\t\t\t\t\t$mtimeFromRequest\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\treturn (int)$mtimeFromRequest;\n\t}\n}\n","sourceCodeStart":11,"sourceCodeEnd":40,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/Connector/Sabre/MtimeSanitizer.php#L11-L40","documentation":"Second guard in MtimeSanitizer::sanitizeMtime() (apps/dav/lib/Connector/Sabre/MtimeSanitizer.php:29): the header was numeric, but its integer value is <= 24*60*60 (86400, one day worth of seconds). Nextcloud rejects these because timestamps that small are never legitimate mtimes — they are almost certainly relative offsets (e.g. seconds elapsed since upload start) or garbage, and accepting them would make files appear to be from 1970-01-01/02 and break sync and versioning logic.","triggerScenarios":"PUT / chunked-upload MOVE / bulk upload with X-OC-MTime: 3600, X-OC-MTime: 0, X-OC-MTime: 86400, or a negative value; also millisecond overflow mistakes are not caught here but second-vs-millisecond confusion can produce small values after (int) truncation in client code, e.g. sending (time() % 100000).","commonSituations":"Client code that computes mtime as a duration or offset instead of an absolute epoch; hardcoded 0 or 1 as a placeholder; unit tests sending arbitrary small integers; scripts where a variable was never initialized and casts to 0.","solutions":["Send an absolute unix timestamp in seconds greater than 86400, e.g. X-OC-MTime: 1706544000.","If your value is in milliseconds, divide by 1000: intdiv($mtimeMs, 1000).","Omit the header if you have no meaningful mtime — the server assigns the current time.","In client code, derive the value from the local file: stat(file).st_mtime / filemtime()."],"exampleFix":"// before\n$client->request('PUT', $url, ['headers' => ['X-OC-MTime' => (string)$elapsedSecondsSinceStart]]);\n\n// after\n$client->request('PUT', $url, ['headers' => ['X-OC-MTime' => (string)filemtime($localPath)]]);","handlingStrategy":"validation","validationCode":"$mtime = filemtime($localPath);\nif ($mtime === false || $mtime <= 86400) {\n    $headers = []; // no meaningful mtime -> let server stamp upload time\n} else {\n    $headers = ['X-OC-MTime' => (string)$mtime];\n}","typeGuard":"function isPositiveUnixTimestamp(string $value): bool {\n    return is_numeric($value) && (int)$value > 24 * 60 * 60;\n}","tryCatchPattern":"try {\n    $mtime = MtimeSanitizer::sanitizeMtime($headerValue);\n} catch (\\InvalidArgumentException $e) {\n    // header rejected as not-a-valid-timestamp; regenerate from filemtime() or drop it\n    $mtime = null;\n}","preventionTips":["Convert millisecond timestamps with intdiv($ms, 1000).","Never send relative offsets or durations in X-OC-MTime.","Assert the value is > 86400 in client upload pipelines."],"tags":["dav","header-validation","mtime","upload","bad-request"],"backgroundTag":"invalid-request-header","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}