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:
I can recommend to create a backup of your library file and then to use the 50/50 rule of debugging:
-
Delete half of your library entries
-
Check if it is now possible to open your library without errors.
-
Delete another half of your remaining library
-
Check if it is now possible to open your library without errors.
-
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
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)
For the command line usage you have to call the bat (or for Linux, lib\runtime\bin\JabRef
)
\JabRef\runtime\bin\JabRef.bat
--console
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)
Maybe you can create a screenshot of the error message. Also, I am curious about the couple problems you found
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.
Thanks for the script! I think this will be really useful. And I agree that it is also useful to export the import errors.