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

The {http://nextcloud.com/ns}filter element is required for

Error message

The {http://nextcloud.com/ns}filter element is required for this request

What it means

CalendarSearchReport::xmlDeserialize() collects the parsed children of the {http://nextcloud.com/ns}search-report payload and throws Sabre\DAV\Exception\BadRequest (HTTP 400) when no {http://nextcloud.com/ns}filter element was among them. The filter block (with comps/props/params/search-term) is the mandatory core of the Nextcloud calendar search REPORT.

Source

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

							}
							$newProps['filters']['params'][] = $subElem['value'];
						} elseif ($subElem['name'] === '{' . SearchPlugin::NS_Nextcloud . '}search-term') {
							$newProps['filters']['search-term'] = $subElem['value'];
						}
					}
					break;
				case '{' . SearchPlugin::NS_Nextcloud . '}limit':
					$newProps['limit'] = $elem['value'];
					break;
				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) {

View on GitHub (pinned to ecdeb153ff)

Solutions

  1. Wrap the search criteria in a filter element: <n:filter>...</n:filter> containing comp-filter(s) and search-term
  2. Reject empty search requests client-side before issuing the REPORT
  3. Compare your payload with a working example captured from the Nextcloud web UI search

Example fix

// before
<n:search-report xmlns:n="http://nextcloud.com/ns"><n:limit>10</n:limit></n:search-report>

// after
<n:search-report xmlns:n="http://nextcloud.com/ns">
  <n:filter>
    <n:comp-filter name="VEVENT"/>
    <n:prop-filter name="SUMMARY"/>
    <n:search-term>meeting</n:search-term>
  </n:filter>
  <n:limit>10</n:limit>
</n:search-report>
Defensive patterns

Strategy: validation

Validate before calling

function buildSearchReport(array $filters, string $term): string {
    if ($filters === []) {
        throw new InvalidArgumentException('n:filter with comps+props is required');
    }
    // ... emit <n:filter> wrapping comps, props and search-term
}

Type guard

function hasFilterElement(string $xmlBody): bool {
    return str_contains($xmlBody, '<n:filter');
}

Try / catch

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

Prevention

When it happens

Trigger: Sending a search REPORT whose body has limit/offset (or nothing at all) but no <n:filter>...</n:filter> element.

Common situations: Clients treating filter as optional because other REPORT types allow empty bodies; partial JSON-to-XML conversion dropping the filter object; schema drift between client and server versions.

Related errors


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