{"record":{"id":"78b0c1cd2614448c","repo":"nextcloud/server","slug":"http-nextcloud-com-ns-prop-filter-or-http-ne","errorCode":null,"errorMessage":"{http://nextcloud.com/ns}prop-filter or {http://nextcloud.com/ns}param-filter given without any {http://nextcloud.com/ns}comp-filter","messagePattern":"(.+?)prop-filter or (.+?)param-filter given without any (.+?)comp-filter","errorType":"http","errorClass":"Sabre\\DAV\\Exception\\BadRequest","httpStatus":400,"severity":"error","filePath":"apps/dav/lib/CalDAV/Search/Xml/Request/CalendarSearchReport.php","lineNumber":137,"sourceCode":"\t\t\t\t\tbreak;\n\t\t\t\tcase '{' . SearchPlugin::NS_Nextcloud . '}limit':\n\t\t\t\t\t$newProps['limit'] = $elem['value'];\n\t\t\t\t\tbreak;\n\t\t\t\tcase '{' . SearchPlugin::NS_Nextcloud . '}offset':\n\t\t\t\t\t$newProps['offset'] = $elem['value'];\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\t\t}\n\n\t\tif (empty($newProps['filters'])) {\n\t\t\tthrow new BadRequest('The {' . SearchPlugin::NS_Nextcloud . '}filter element is required for this request');\n\t\t}\n\n\t\t$propsOrParamsDefined = (!empty($newProps['filters']['props']) || !empty($newProps['filters']['params']));\n\t\t$noCompsDefined = empty($newProps['filters']['comps']);\n\t\tif ($propsOrParamsDefined && $noCompsDefined) {\n\t\t\tthrow new BadRequest('{' . SearchPlugin::NS_Nextcloud . '}prop-filter or {' . SearchPlugin::NS_Nextcloud . '}param-filter given without any {' . SearchPlugin::NS_Nextcloud . '}comp-filter');\n\t\t}\n\n\t\tif (!isset($newProps['filters']['search-term'])) {\n\t\t\tthrow new BadRequest('{' . SearchPlugin::NS_Nextcloud . '}search-term is required for this request');\n\t\t}\n\n\t\tif (empty($newProps['filters']['props']) && empty($newProps['filters']['params'])) {\n\t\t\tthrow new BadRequest('At least one{' . SearchPlugin::NS_Nextcloud . '}prop-filter or {' . SearchPlugin::NS_Nextcloud . '}param-filter is required for this request');\n\t\t}\n\n\t\t$obj = new self();\n\t\tforeach ($newProps as $key => $value) {\n\t\t\t$obj->$key = $value;\n\t\t}\n\t\treturn $obj;\n\t}\n}\n","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/CalDAV/Search/Xml/Request/CalendarSearchReport.php#L119-L155","documentation":"Structural check in CalendarSearchReport::xmlDeserialize(): the parsed filter contains prop-filters or param-filters but no comp-filter, so the server cannot know which component type (VEVENT/VTODO/VJOURNAL) to search and answers Sabre\\DAV\\Exception\\BadRequest (HTTP 400). prop-filter and param-filter are only meaningful nested under a comp-filter.","triggerScenarios":"Sending <n:filter><n:prop-filter name=\"SUMMARY\"/><n:search-term>x</n:search-term></n:filter> without a <n:comp-filter name=\"VEVENT\"/>.","commonSituations":"Client search forms that let users pick properties but no component type; copy-pasted payload fragments from a larger example losing the outer comp-filter.","solutions":["Add a comp-filter naming the component type around/next to your prop and param filters","Default the component selector to VEVENT in your UI when the user does not choose","Validate the filter tree client-side: props/params present implies at least one comps entry"],"exampleFix":"// before\n<n:filter>\n  <n:prop-filter name=\"SUMMARY\"/>\n  <n:search-term>meeting</n:search-term>\n</n:filter>\n\n// after\n<n:filter>\n  <n:comp-filter name=\"VEVENT\"/>\n  <n:prop-filter name=\"SUMMARY\"/>\n  <n:search-term>meeting</n:search-term>\n</n:filter>","handlingStrategy":"validation","validationCode":"$hasComps = $comps !== [];\n$hasPropsOrParams = $props !== [] || $params !== [];\nif ($hasPropsOrParams && !$hasComps) {\n    $comps = ['VEVENT']; // or throw: prop/param filters require a comp-filter\n}","typeGuard":"function isValidFilterShape(array $comps, array $props, array $params): bool {\n    return ($props === [] && $params === []) || $comps !== [];\n}","tryCatchPattern":"try {\n    $client->request('REPORT', $calendarUri, $xmlBody);\n} catch (\\Sabre\\Http\\ClientException $e) {\n    if ($e->getResponse()?->getStatus() === 400) { /* add comp-filter for the component type */ }\n}","preventionTips":["Model the filter as comps -> props -> params tree in code so structure cannot be flat","Default component type to VEVENT in search UIs","Validate the tree shape before serialization"],"tags":["caldav","xml","search","nextcloud","bad-request","comp-filter"],"backgroundTag":"webdav-400-bad-request","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}