Export list of import errors

I am getting a series of errors when opening a library file, (Error parsing entry, expected = but received ) etc.).
The list is too long to display, is there a way to export this list to a file?

you can press CTRL + A, which will select all text, then copy (CTRL+ C) and paste (CTRL + V) the error message into a text file.

You also can check JabRef’s log files. Where to find them:

1 Like

I can recommend to create a backup of your library file and then to use the 50/50 rule of debugging:

  1. Delete half of your library entries

  2. Check if it is now possible to open your library without errors.

  3. Delete another half of your remaining library

  4. Check if it is now possible to open your library without errors.

  5. Repeat

It’s like cutting a cake into ever smaller pieces, while trying to find the hidden surprise within. This process of elimination will very quickly allow you to stumple upon the part of your library that causes the error. Cut until you fail to hit upon the error and then cut some more.

1 → 1/2 → 1/4 → 1/8 → 1/16 → 1/32 → 1/64

1 Like

Thanks @ThiloteE !

FYI:, on my system I can’t select the text in the error window (Jabref 5.8 on Windows 10), also the log files have INFO messages with the file name that was opened, but no indication that an import error happened.

I also tried running JabRef on the command line, but it doesn’t log the errors to the console either (or logfile).

–console -importBibtex ‘.\conten.bib’ --debug -n

I made a small script to bisect the file manually and found a couple problems in my file.

Is there any command line option to let Jabref validate a file? Then I could automate the script below.

import os.path
import io

inputFile = "content full.bib" 
logFile = os.path.splitext(inputFile)[0] + '.log'

def writefile(content:list[str], filename:str, label:str) -> str:
    name, ext = os.path.splitext(filename)
    newname = name + label + ext
    with open(newname, 'w', encoding='utf-8') as f:
        f.writelines(content)
    return newname


def bisect(filename:str, logFile:io.TextIOBase):
    content = open(filename, 'r', encoding='utf-8').readlines()
    msg = input(f'Open file "{filename}" and enter error message, press Enter if no errors: ')
    logFile.write(f"{filename}: {msg}\n")
    if msg == '':
        return # no errors

    entryStartLines = [n for n,l in enumerate(content) if l.strip().startswith('@')]
    if len(entryStartLines) == 1:
        return # only one entry left, nothing to bisect

    pivot =  entryStartLines[int(len(entryStartLines) / 2)]
    
    top = content[:pivot]
    bisect(writefile(top, filename, 'T'), logFile)
    bottom = content[pivot:]
    bisect(writefile(bottom, filename, 'B'), logFile)

if __name__=='__main__':
    with open(logFile, 'w', encoding='utf-8') as log:
        bisect(filename=inputFile, logFile=log)
1 Like

For the command line usage you have to call the bat (or for Linux, lib\runtime\bin\JabRef)
\JabRef\runtime\bin\JabRef.bat --console

1 Like

Thanks, @ThiloteE and @Siedlerchr, for your help.

Here is a program that automates the search and isolates the offending entries:

# Bisect Bibtex files to find errors using JabRef as a validator
# MIT License
import os.path
import io
import subprocess

# Folder that contains JabRef.bat
pathToJabref = r'C:\Users\zui\Downloads\JabRef-5.8-portable_windows\JabRef\runtime\bin'
# The file to be checked. Spaces in path might cause problems
inputFile = "contentfull.bib" 

# Output is written to this file
logFile = os.path.splitext(inputFile)[0] + '.log'

def writefile(content:list[str], filename:str, label:str) -> str:
    name, ext = os.path.splitext(filename)
    newname = name + label + ext
    with open(newname, 'w', encoding='utf-8') as f:
        f.writelines(content)
    return newname


def validateBibFile(filename:str):
    '''Test a file
    Return error string if error or empty string if no error'''
    cmd = os.path.join(pathToJabref, f"JabRef.bat --console -n  -i {os.path.abspath(filename)},bibtex")
    ret = subprocess.check_output(cmd).decode("utf-8")
    print(ret)
    if 'Error' in ret:
        return ' '.join(ret.split('\n')[1:])
    else:
        return ''
    

def bisect(filename:str, logFile:io.TextIOBase):
    msg = validateBibFile(filename)
    logFile.write(f"{filename}: {msg}\n")
    logFile.flush()
    if msg == '':
        return # no errors

    content = open(filename, 'r', encoding='utf-8').readlines()
    entryStartLines = [n for n,l in enumerate(content) if l.strip().startswith('@')] # line numbers where bibtex entries start
    if len(entryStartLines) == 1:
        # save the file as a minimal error
        name, ext = os.path.splitext(filename)
        newname = name + "minErr" + ext
        print(f"Found minimal example, saving to {newname}")
        with open(newname, 'w', encoding='utf-8') as f:
            f.write(f'@Comment {msg}\n\n')
            f.writelines(content)
        return # only one entry left, nothing to bisect

    pivot =  entryStartLines[int(len(entryStartLines) / 2)]
    
    top = content[:pivot]
    bisect(writefile(top, filename, 'T'), logFile)
    bottom = content[pivot:]
    bisect(writefile(bottom, filename, 'B'), logFile)

if __name__=='__main__':
    with open(logFile, 'w', encoding='utf-8') as log:
        bisect(filename=inputFile, logFile=log)


2 Likes

Maybe you can create a screenshot of the error message. Also, I am curious about the couple problems you found :slight_smile:

Here you go:


The problems were:

  • random { and } sprinkled through the abstracts from OCR errors.
  • a couple of strange characters, line and paragraph separators, non breaking spaces, zero width spaces etc. I don’t know which of those were a problem, I just replaced them all.
1 Like

Thanks for the script! I think this will be really useful. And I agree that it is also useful to export the import errors.