nextcloud/server · error · Sabre\DAV\Exception\BadRequest

{http://nextcloud.com/ns}search-term is required for this re

Error message

{http://nextcloud.com/ns}search-term is required for this request

What it means

CalendarSearchReport::xmlDeserialize() requires a {http://nextcloud.com/ns}search-term inside the filter; when filters were given but isset($newProps['filters']['search-term']) is false it throws Sabre\DAV\Exception\BadRequest (HTTP 400). The Nextcloud search REPORT always performs substring matching, so the term is not optional.

Source

Thrown at apps/dav/lib/CalDAV/Search/Xml/Request/CalendarSearchReport.php:141

				case '{' . SearchPlugin::NS_Nextcloud . '}offset':
					$newProps['offset'] = $elem['value'];
					break;

			}
		}

		if (empty($newProps['filters'])) {
			throw new BadRequest('The {' . SearchPlugin::NS_Nextcloud . '}filter element is required for this request');
		}

		$propsOrParamsDefined = (!empty($newProps['filters']['props']) || !empty($newProps['filters']['params']));
		$noCompsDefined = empty($newProps['filters']['comps']);
		if ($propsOrParamsDefined && $noCompsDefined) {
			throw new BadRequest('{' . SearchPlugin::NS_Nextcloud . '}prop-filter or {' . SearchPlugin::NS_Nextcloud . '}param-filter given without any {' . SearchPlugin::NS_Nextcloud . '}comp-filter');
		}

		if (!isset($newProps['filters']['search-term'])) {
			throw new BadRequest('{' . SearchPlugin::NS_Nextcloud . '}search-term is required for this request');
		}

		if (empty($newProps['filters']['props']) && empty($newProps['filters']['params'])) {
			throw new BadRequest('At least one{' . SearchPlugin::NS_Nextcloud . '}prop-filter or {' . SearchPlugin::NS_Nextcloud . '}param-filter is required for this request');
		}

		$obj = new self();
		foreach ($newProps as $key => $value) {
			$obj->$key = $value;
		}
		return $obj;
	}
}

View on GitHub (pinned to ecdeb153ff)

Solutions

  1. Add <n:search-term>...</n:search-term> inside <n:filter>
  2. For listing without a term, use a plain calender-query REPORT (time-range filter) or PROPFIND instead of the Nextcloud search report
  3. Guard client-side: if the term is empty, either block the request or switch to the listing query

Example fix

// before
<n:filter><n:comp-filter name="VEVENT"/><n:prop-filter name="SUMMARY"/></n:filter>

// after
<n:filter>
  <n:comp-filter name="VEVENT"/>
  <n:prop-filter name="SUMMARY"/>
  <n:search-term>meeting</n:search-term>
</n:filter>
Defensive patterns

Strategy: validation

Validate before calling

if (!isValidSearchTerm($term)) {
    // switch to a plain calendar-query REPORT / PROPFIND for listing, or require a term
    throw new InvalidArgumentException('search-term is required');
}

Type guard

function reportHasSearchTerm(array $newProps): bool {
    return isset($newProps['filters']['search-term'])
        && is_string($newProps['filters']['search-term']);
}

Try / catch

try {
    $client->request('REPORT', $calendarUri, $xmlBody);
} catch (\Sabre\Http\ClientException $e) {
    if ($e->getResponse()?->getStatus() === 400) { /* add <n:search-term> inside n:filter */ }
}

Prevention

When it happens

Trigger: Sending a filter block with comp-filter and prop-filter elements but no <n:search-term>text</n:search-term> child.

Common situations: Attempting a 'list all events' style query by omitting the term; client versions that modeled search-term as optional; empty term serialized as a missing element.

Related errors


AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17). Data as JSON: /api/errors/19e2046a102be42f. Report an issue: GitHub.