{"record":{"id":"84776297ea36c4d8","repo":"zylon-ai/private-gpt","slug":"start-on-can-only-be-used-with-last-strategy","errorCode":null,"errorMessage":"start_on can only be used with 'last' strategy","messagePattern":"start_on can only be used with 'last' strategy","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/components/memory/trimming_memory.py","lineNumber":99,"sourceCode":"\n        # Validate tokenizer\n        tokenizer_fn = values.get(\"tokenizer_fn\")\n        if tokenizer_fn is None:\n            # TODO: Replace with a default tokenizer function\n            raise ValueError(\"tokenizer_fn must be provided.\")\n\n        # Validate text splitter\n        text_splitter = values.get(\"text_splitter\")\n        if text_splitter is None:\n            values[\"text_splitter\"] = _default_text_splitter\n\n        # Validate strategy-specific constraints\n        trim_strategy = values.get(\"trim_strategy\", TrimStrategy.LAST)\n        start_on = values.get(\"start_on\")\n        include_system = values.get(\"include_system\", True)\n\n        if start_on and trim_strategy == TrimStrategy.FIRST:\n            raise ValueError(\"start_on can only be used with 'last' strategy\")\n\n        if include_system and trim_strategy == TrimStrategy.FIRST:\n            raise ValueError(\"include_system can only be used with 'last' strategy\")\n\n        return values\n\n    @classmethod\n    def from_defaults(\n        cls,\n        chat_history: list[ChatMessage] | None = None,\n        llm: LLM | None = None,\n        chat_store: BaseChatStore | None = None,\n        chat_store_key: str = DEFAULT_CHAT_STORE_KEY,\n        token_limit: int | None = None,\n        trim_strategy: TrimStrategy = TrimStrategy.LAST,\n        include_system: bool = True,\n        allow_partial: bool = False,\n        start_on: MessageRole | list[MessageRole] | None = None,","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/memory/trimming_memory.py#L81-L117","documentation":"Raised by the TrimmingMemory validator when start_on is set while trim_strategy is TrimStrategy.FIRST. start_on defines a role boundary to resume history from during LAST-strategy trimming (keep newest messages, starting from a given role); it is meaningless for FIRST strategy (keep oldest messages), so the combination is rejected at construction rather than ignored.","triggerScenarios":"TrimmingMemory(trim_strategy=TrimStrategy.FIRST, start_on=MessageRole.USER); passing start_on='user' together with trim_strategy='first' through config or from_defaults kwargs.","commonSituations":"Copy-pasting a full config block between memory instances that use different strategies; refactoring from LAST to FIRST trimming and leaving start_on in place; config schemas that allow all fields simultaneously without cross-field validation.","solutions":["Drop start_on when using TrimStrategy.FIRST.","Keep start_on only with the default LAST strategy (optionally as a role or list of roles).","Add cross-field validation in your config loader so start_on and FIRST cannot be combined."],"exampleFix":"# before\nTrimmingMemory(trim_strategy=TrimStrategy.FIRST, start_on=MessageRole.USER, ...)\n\n# after\nTrimmingMemory(trim_strategy=TrimStrategy.FIRST, ...)\n# or keep start_on with LAST:\nTrimmingMemory(trim_strategy=TrimStrategy.LAST, start_on=MessageRole.USER, ...)","handlingStrategy":"validation","validationCode":"if trim_strategy == 'first':\n    start_on = None  # only valid with 'last'\nmem = Memory.from_defaults(type='trim', trim_strategy=trim_strategy, start_on=start_on)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Cross-field-validate memory config: start_on/end_on only with LAST strategy.","When flipping strategies in config, review all boundary options (start_on, include_system) in the same change."],"tags":["memory","validation","configuration","trimming"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}