{"record":{"id":"d1d60fff46db60b9","repo":"roboflow/supervision","slug":"cannot-append-to-csv-the-file-self-file-name","errorCode":null,"errorMessage":"Cannot append to CSV: The file '{self.file_name}' is not open.","messagePattern":"Cannot append to CSV: The file '(.+?)' is not open\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/supervision/detection/tools/csv_sink.py","lineNumber":214,"sourceCode":"            parsed_rows.append(row)\n        return parsed_rows\n\n    def append(\n        self, detections: Detections, custom_data: dict[str, Any] | None = None\n    ) -> None:\n        \"\"\"\n        Append detection data to the CSV file.\n\n        Args:\n            detections: The detection data.\n            custom_data: Custom data to include. Scalars, dictionaries, and\n                other non-sequence values are broadcast to every detection in\n                this batch. NumPy arrays, lists, and tuples with length equal\n                to ``len(detections)`` are sliced per detection; other lists\n                and tuples are broadcast unchanged.\n        \"\"\"\n        if not self.writer:\n            raise Exception(\n                f\"Cannot append to CSV: The file '{self.file_name}' is not open.\"\n            )\n        field_names = CSVSink.parse_field_names(detections, custom_data)\n        if not self.header_written:\n            self.field_names = field_names\n            self.writer.writerow(field_names)\n            self.header_written = True\n\n        if field_names != self.field_names:\n            logger.warning(\n                \"Field names do not match the header. Expected: %s, given: %s\",\n                self.field_names,\n                field_names,\n            )\n\n        parsed_rows = CSVSink.parse_detection_data(detections, custom_data)\n        for row in parsed_rows:\n            self.writer.writerow(","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/detection/tools/csv_sink.py#L196-L232","documentation":"CSVSink raises this generic Exception from append() when its internal csv writer is None, i.e. the sink is not inside its opened context. CSVSink opens the file lazily via the context-manager protocol (__enter__), so append() is only valid inside a `with CSVSink(...) as sink:` block.","triggerScenarios":"Creating sink = CSVSink('out.csv') and calling sink.append(detections) without entering the with block; or calling append() after the with block has exited (file already closed).","commonSituations":"Migrating code that assumed the constructor opens the file (older examples or other sinks like JSONSink behave differently); storing the sink on a class and appending from another method after the context exited; reusing a sink across video loops where only the first loop is inside the with.","solutions":["Wrap usage in the context manager: with CSVSink('out.csv') as sink: sink.append(detections).","Keep the entire detection loop inside the with block so append always has an open writer.","If appending from multiple places, open the sink once and pass it down while the context is still active.","Do not call append() after __exit__; create a new CSVSink for a new session."],"exampleFix":"# before\nsink = CSVSink(\"out.csv\")\nsink.append(detections)  # Exception: file is not open\n\n# after\nwith CSVSink(\"out.csv\") as sink:\n    for frame in video:\n        detections = model(frame)\n        sink.append(detections)","handlingStrategy":"try-catch","validationCode":"if getattr(sink, \"writer\", None) is None:\n    raise RuntimeError(\"CSVSink not open; use 'with CSVSink(...) as sink:'\")\nsink.append(detections)","typeGuard":null,"tryCatchPattern":"try:\n    sink.append(detections)\nexcept Exception as exc:\n    if \"not open\" in str(exc):\n        logger.error(\"CSVSink used outside its context manager\")\n        raise\n    raise","preventionTips":["Always open CSVSink via 'with' and keep the processing loop inside the block.","Structure code so the sink is passed down while its context is active.","Create a new sink per output session; never reuse one after __exit__."],"tags":["csv-sink","context-manager","lifecycle","exception"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}