dgtlmoon/changedetection.io · error · BadRequest

Validation failed: {'; '.join(error_details)}

Error message

Validation failed: {'; '.join(error_details)}

What it means

A catch-all bare `except:` in the XPath validator catches any non-XPathEvalError exception thrown while compiling the expression (or while acquiring the lxml lock / building the parser). It signals an unexpected system-level failure rather than a pure syntax error, and masks the original exception's details.

Source

Thrown at changedetectionio/api/__init__.py:214

                            # match the OpenAPI server definitions, causing false positives.
                            if isinstance(error, PathError):
                                logger.debug(f"API Call - Skipping path/server validation (delegated to Flask): {error}")
                                continue

                            error_str = str(error)
                            # Extract detailed schema errors from __cause__
                            if hasattr(error, '__cause__') and hasattr(error.__cause__, 'schema_errors'):
                                for schema_error in error.__cause__.schema_errors:
                                    field = '.'.join(str(p) for p in schema_error.path) if schema_error.path else 'body'
                                    msg = schema_error.message if hasattr(schema_error, 'message') else str(schema_error)
                                    error_details.append(f"{field}: {msg}")
                            else:
                                error_details.append(error_str)

                        # Only raise if we have actual validation errors (not path/server issues)
                        if error_details:
                            logger.error(f"API Call - Validation failed: {'; '.join(error_details)}")
                            raise BadRequest(f"Validation failed: {'; '.join(error_details)}")
            except BadRequest:
                # Re-raise BadRequest exceptions (validation failures)
                raise
            except Exception as e:
                # If OpenAPI spec loading fails, log but don't break existing functionality
                logger.critical(f"OpenAPI validation warning for {operation_id}: {e}")
                abort(500)
            return f(*args, **kwargs)
        return wrapper
    return decorator

# Import all API resources
from .Watch import Watch, WatchHistory, WatchSingleHistory, WatchHistoryDiff, CreateWatch, WatchFavicon
from .Tags import Tags, Tag
from .Import import Import
from .SystemInfo import SystemInfo
from .Spec import Spec
from .Notifications import Notifications

View on GitHub (pinned to 5d9c7c6da7)

Solutions

  1. Check server logs / reproduce the compile locally to find the real exception
  2. Verify lxml is properly installed and version-matched (pip install -U lxml) and the parser is not shared unsafely across threads
  3. If you control the code, log the real exception before raising the generic message

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

null

Try / catch

try:
    tree.xpath(expr)
except etree.XPathEvalError:
    handle_syntax_error()
except Exception as e:
    log.exception('unexpected lxml failure')
    handle_system_error(e)

Prevention

When it happens

Trigger: lxml raising MemoryError, KeyboardInterrupt-style exceptions, parser instantiation failure, or lxml_guard lock errors while tree.xpath(line) runs; any unexpected exception type other than etree.XPathEvalError escaping the compile step.

Common situations: Broken lxml installation or version mismatch where html.fromstring or the shared parser misbehaves; concurrency issues around the shared lxml parser; thread interruption during validation. Rare in practice; almost all bad input hits the XPathEvalError branch instead.

Related errors


AI-assisted analysis of dgtlmoon/changedetection.io@5d9c7c6da7 (2026-08-27). Data as JSON: /api/errors/18e0adc3ed82aeae. Report an issue: GitHub.