cakephp/cakephp · error · CakeException

Invalid cache time value

Error message

Invalid cache time value `%s`

What it means

AssetMiddleware's deliverAsset() parses the configured cacheTime string with strtotime() to compute an Expires header. When strtotime() cannot parse the value it returns false, meaning the middleware's cacheTime option is not a valid strtotime() expression. CakePHP throws this to fail fast rather than emit bogus cache headers.

Solutions

  1. Fix the cacheTime option to a valid strtotime() string, e.g. '+1 day', '+2 weeks', '+1 month'.
  2. If config comes from environment/config file, validate it with strtotime($value) !== false at bootstrap and fail early.
  3. If a fixed timestamp is desired, pre-compute with strtotime() before passing it in.

Example fix

// before
new AssetMiddleware(['cacheTime' => 'in one day']);
// after
new AssetMiddleware(['cacheTime' => '+1 day']);
Defensive patterns

Strategy: validation

Validate before calling

$cacheTime = '+1 day';
if (strtotime($cacheTime) === false) {
    throw new InvalidArgumentException("cacheTime must be a valid strtotime() expression, got '$cacheTime'");
}

Type guard

function isStrToTimeable(string $value): bool { return strtotime($value) !== false; }

Prevention

When it happens

Trigger: Setting the 'cacheTime' option on AssetMiddleware to a string strtotime() cannot parse, e.g. 'in 1 day', '+1w eek', an integer-like overflow string, or an empty string.

Common situations: Typos in the cacheTime config in middleware definition; copying '+1 week' as '1 week +'; using locale-formatted dates strtotime can't parse; passing a relative time from an env var that was mangled.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of cakephp/cakephp@1128eba9b0 (2026-09-12). Data as JSON: /api/errors/295cb6361bb5fef0. Report an issue: GitHub.

Appendix: source

Thrown at src/Routing/Middleware/AssetMiddleware.php:164

     * @param \Psr\Http\Message\ServerRequestInterface $request The request object to use.
     * @param \SplFileInfo $file The file wrapper for the file.
     * @return \Cake\Http\Response The response with the file & headers.
     */
    protected function deliverAsset(ServerRequestInterface $request, SplFileInfo $file): Response
    {
        $resource = fopen($file->getPathname(), 'rb');
        if ($resource === false) {
            throw new CakeException(sprintf('Cannot open resource `%s`', $file->getPathname()));
        }
        $stream = new Stream($resource);

        $response = new Response(['stream' => $stream]);

        $contentType = MimeType::getMimeTypeForFile($file->getRealPath());
        $modified = $file->getMTime();
        $expire = strtotime($this->cacheTime);
        if ($expire === false) {
            throw new CakeException(sprintf('Invalid cache time value `%s`', $this->cacheTime));
        }

        $now = time();
        $maxAge = $expire - $now;

        return $response
            ->withHeader('Content-Type', $contentType)
            ->withHeader('Cache-Control', 'public,max-age=' . $maxAge)
            ->withHeader('Date', DateTime::parse($now)->toRfc7231String())
            ->withHeader('Last-Modified', DateTime::parse($modified)->toRfc7231String())
            ->withHeader('Expires', DateTime::parse($expire)->toRfc7231String());
    }
}

View on GitHub (pinned to 1128eba9b0)