plandex-ai/plandex · error

error reading description file %s: %v

Error message

error reading description file %s: %v

What it means

Inside each per-file goroutine of GetConvoMessageDescriptions, os.ReadFile loads the description JSON. Any read failure is wrapped as 'error reading description file %s: %v' naming the file and sent to errCh, which the collector turns into 'error reading description files: ...' and aborts the entire descriptions load.

Source

Thrown at app/server/db/result_helpers.go:340

	errCh := make(chan error, len(files))
	descCh := make(chan *ConvoMessageDescription, len(files))

	for _, file := range files {
		go func(file os.DirEntry) {
			defer func() {
				if r := recover(); r != nil {
					log.Printf("panic in GetConvoMessageDescriptions: %v\n%s", r, debug.Stack())
					errCh <- fmt.Errorf("panic in GetConvoMessageDescriptions: %v\n%s", r, debug.Stack())
					runtime.Goexit() // don't allow outer function to continue and double-send to channel
				}
			}()
			path := filepath.Join(descriptionsDir, file.Name())

			bytes, err := os.ReadFile(path)

			if err != nil {
				errCh <- fmt.Errorf("error reading description file %s: %v", file.Name(), err)
				return
			}

			var description ConvoMessageDescription
			err = json.Unmarshal(bytes, &description)

			if err != nil {
				log.Println("Error unmarshalling description file:", path)
				log.Println("bytes:")
				log.Println(string(bytes))

				errCh <- fmt.Errorf("error unmarshalling description file %s: %v", path, err)
				return
			}

			descCh <- &description
		}(file)
	}

View on GitHub (pinned to e2d772072e)

Solutions

  1. Identify the failing file from the message and check whether it still exists and is readable
  2. Check permissions/ownership of that file and the descriptions directory for the server user
  3. Remove non-regular entries (directories, sockets) from the descriptions dir or filter them with file.Type().IsRegular()
  4. Stop concurrent cleanup processes from racing with reads, or tolerate individual file misses by skipping on os.IsNotExist
  5. Investigate filesystem health if the inner error is an I/O error (EIO), remounting or repairing the volume

Example fix

// before
bytes, err := os.ReadFile(path)
if err != nil {
    errCh <- fmt.Errorf("error reading description file %s: %v", file.Name(), err)
    return
}
// after
bytes, err := os.ReadFile(path)
if err != nil {
    if os.IsNotExist(err) {
        descCh <- nil // file vanished between listing and read; skip it
        return
    }
    errCh <- fmt.Errorf("error reading description file %s: %v", file.Name(), err)
    return
}
Defensive patterns

Strategy: validation

Validate before calling

func descriptionFileReadable(dir string, name string) error {
    path := filepath.Join(dir, name)
    info, err := os.Stat(path)
    if err != nil {
        return err
    }
    if !info.Mode().IsRegular() {
        return fmt.Errorf("%s is not a regular file", path)
    }
    f, err := os.Open(path)
    if err != nil {
        return err
    }
    return f.Close()
}

Type guard

func isDescriptionFileReadError(err error) bool {
    return err != nil && strings.Contains(err.Error(), "error reading description file")
}

Try / catch

descriptions, err := GetConvoMessageDescriptions(orgId, planId)
if err != nil {
    if isDescriptionFileReadError(err) {
        var badFile string
        fmt.Sscanf(err.Error(), "error reading description files: error reading description file %s", &badFile)
        log.Printf("unreadable description file %q; repair or remove it", badFile)
        return nil, err
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling GetConvoMessageDescriptions when a listed description file cannot be read: it was deleted between ReadDir and ReadFile, permissions changed, it is a directory/special file inside descriptionsDir, or the underlying filesystem returns an I/O error.

Common situations: Another process (cleanup job, concurrent plan reset) deleting description files while this read runs; permission drift after container image updates or user changes; a subdirectory accidentally created inside descriptionsDir; read-only remount of the data volume.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/7b995fd64c7379a8. Report an issue: GitHub.