Skip to content

bug(warehouse/identity): file descriptor leak in uploadFile() — outputFile never closed #7185

Description

@andyosyndoh

Bug Description

In warehouse/identity/identity.go, the uploadFile() method opens the load file for uploading to object storage but never closes the file descriptor — on any path (filemanager creation error, upload error, or success).

This is the same defect class as #7071 (batchrouter upload()), but in the identity-resolution flow, which was not covered by that report.

Location

warehouse/identity/identity.go — function uploadFile(), line 455

Code

func (idr *Identity) uploadFile(ctx context.Context, filePath string, txn *sqlmiddleware.Tx, tableName string, totalRecords int) (err error) {
	outputFile, err := os.Open(filePath)
	if err != nil {
		panic(err)
	}
	// ❌ no defer outputFile.Close() anywhere in the function

	storageProvider := warehouseutils.ObjectStorageType(...)
	uploader, err := filemanager.New(&filemanager.Settings{...})
	if err != nil {
		return err                                  // fd leaked
	}
	output, err := uploader.Upload(ctx, outputFile, ...)
	if err != nil {
		return err                                  // fd leaked
	}
	// ...
	return err                                      // fd also leaked on success
}

Impact

uploadFile() is called twice per identity-resolution sync — once for merge rules (processMergeRules, line 570) and once for identity mappings (line 581). Every warehouse sync with identity resolution enabled leaks 2 OS file descriptors for the lifetime of the process. Under sustained syncing this contributes to fd exhaustion (too many open files), the same failure mode described in #7071.

Secondary issue in the same function

A failed os.Open triggers panic(err), crashing the whole server, while every other error path in this function returns an error gracefully. A missing/unreadable temp file should surface as a sync failure, not a process crash.

Expected Behaviour

The file descriptor should be closed once the upload completes (success or failure), and open failure should return an error instead of panicking.

Suggested Fix

outputFile, err := os.Open(filePath)
if err != nil {
	return fmt.Errorf("opening load file %s: %w", filePath, err)
}
defer func() { _ = outputFile.Close() }()

This matches the pattern already used in the same package at identity.go:162 (tableRows.Close()) and in warehouse/validations/validate.go:405-411.

Environment

  • File: warehouse/identity/identity.go
  • Function: uploadFile() (lines 454–494)
  • Affected: all warehouse destinations with identity resolution enabled

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions