alibaba/open-code-review · warning

close session file: %w

Error message

close session file: %w

What it means

After writing the session_end record, WriteSessionEnd closes the session file; a non-nil Close() error is reported as 'close session file' (only if no earlier write error was recorded, so the original cause is preserved). The record itself may have been written correctly — the failure is in committing the file handle back to the OS.

Source

Thrown at internal/session/persist.go:414

		if jw.file != nil {
			jw.file.Close()
		}
		return fmt.Errorf("marshal session_end: %w", err)
	}

	var writeErr error
	if jw.writer != nil {
		if _, err := jw.writer.Write(data); err != nil {
			writeErr = fmt.Errorf("write session_end: %w", err)
		} else if err := jw.writer.WriteByte('\n'); err != nil {
			writeErr = fmt.Errorf("write session_end: %w", err)
		} else if err := jw.writer.Flush(); err != nil {
			writeErr = fmt.Errorf("flush session_end: %w", err)
		}
	}
	if jw.file != nil {
		if err := jw.file.Close(); err != nil && writeErr == nil {
			writeErr = fmt.Errorf("close session file: %w", err)
		}
	}
	return writeErr
}

func (jw *jsonlWriter) flushAndClose() {
	jw.mu.Lock()
	defer jw.mu.Unlock()
	if jw.writer != nil {
		jw.writer.Flush()
	}
	if jw.file != nil {
		jw.file.Close()
	}
}

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Check the wrapped error: 'file already closed' (os.ErrClosed) means a double-close — ensure flushAndClose and WriteSessionEnd are not both invoked on the same jsonlWriter
  2. On NFS, treat close errors as real write failures: verify file integrity or write sessions to local storage
  3. Call errors.Is(err, os.ErrClosed) to distinguish double-close from genuine I/O failure
  4. If the session_end line is present and complete, the data is intact despite the close error

Example fix

// before
jw.flushAndClose()
if err := w.WriteSessionEnd(...); err != nil {...} // double close
// after
if err := w.WriteSessionEnd(...); err != nil {...} // WriteSessionEnd performs the close
Defensive patterns

Strategy: try-catch

Try / catch

if err := writer.WriteSessionEnd(); err != nil {
    if strings.Contains(err.Error(), "close session file") {
        if errors.Is(err, os.ErrClosed) {
            log.Printf("double close bug: %v", err)
        } else {
            log.Printf("possible data loss on close: %v", err)
        }
    }
}

Prevention

When it happens

Trigger: WriteSessionEnd: jw.file.Close() returns an error while writeErr was nil — e.g. buffered data was already fine but close-time flush to physical media failed (NFS), or the fd was already closed elsewhere.

Common situations: Double-close (Close called both by flushAndClose and WriteSessionEnd on the same writer); NFS/fuse filesystems reporting delayed-write errors at close; fd exhaustion cleanup races.

Related errors


AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02). Data as JSON: /api/errors/130f3e98063acc28. Report an issue: GitHub.