Difference between revisions of "Web Report Viewer Troubleshooting"

From ISoft Wiki
Jump to navigationJump to search
 
(38 intermediate revisions by the same user not shown)
Line 3: Line 3:
== Terms ==
== Terms ==


* Crystal Server - the Node.JS application that uses Report Commander to generate the report PDF. Runs on Bunnahabhain
* Crystal Server - the Node.JS application that uses Report Commander to generate the report PDF. Runs on Bunnahabhain. '''This application is not the same as Report Queue.'''
* Report Commander - command line application used to generate report PDFs by the Crystal Server (and Report Queue)
* Report Commander - command line application used to generate report PDFs by the Crystal Server (and Report Queue)
* Report Queue - python application that reads from reportqueue table to send emails and print to a printer. '''Report Queue is separate from Crystal Server, and the two systems do not interact.'''
* Report Queue - python application that reads from reportqueue table to send emails and print to a printer. '''Report Queue is separate from Crystal Server, and the two systems do not interact.'''
Line 9: Line 9:
* reportparameter - a table in the database that associates parameters to reports
* reportparameter - a table in the database that associates parameters to reports


== Common Errors ==
== FAQ ==  


=== Error Running Report ===
=== How does the web report viewer work? ===


This means that Report Commander encountered an error running the report. If you get this error, check the reportqueue error for a more detailed error message. Listed below are some common ones.
Since we can't run crystal reports directly in the browser, we need to run them on a central server and send them back to the web browser. There are multiple servers involved in this process, which I'll outline below


==== "Missing parameter values" or "Double check the parameters..."====
* The report and parameter list are loaded from the application's API (Chromium, Presage API, EE API)
* The user selects a report, fills out parameters, and clicks "Preview"
* A request is sent to the application backend (Chromium, Presage API, EE API)
* Application backend sends a request to Crystal Server, running on Bunnahabhain, or a customer server if relevant. This requests includes details of the report to run, which database to run it on, and a valid session token for that database.
* Bunnahabhain takes this request, and attempts to validate the given session token in the given database. If this fails, such as if the token is invalid or it can't connect to the database, an "Invalid Session" error is thrown.
* After the session is validated, Crystal Server will download the report file from the customer's database, and run default parameter queries. The report is saved to the "cache directory" specified in the config, with the file's hash as the file name.
* Then, Crystal Server creates a command line string to run Report Commander for the given report and parameters
* Report Commander is then invoked to generate the PDF, connecting to the database with ODBC. The PDF is saved to a folder in the Crystal Server's "cache directory". If Report Commander throws an error, it is forwarded to the application API (Chromium, Presage API, EE API), which saves it to the <code>reportqueue</code> table and forwards that error to the client, where it is displayed.
* If it succeeds, the report file is base64 encoded and sent back to the application API (Chromium, Presage API, EE API), along with the time it took to execute the report.
* The application API receives the request, saves the details to <code>reportqueue</code>/<code>reportqueueparameter</code>, and returns the base64 encoded PDF to the client
* The client receives the response from its backend, and displays the base64 encoded PDF in the browser using an <code><object/></code> tag


This means that Report Commander did not receive all required parameters for the report. Often times, the report will run fine on desktop, because the Crystal SDK can "fill in the gaps", while the web Report Viewer cannot, and needs a row in reportparameter for every parameter.
==== How is that different from desktop? ====


===== Solution =====
ITrack desktop talks directly to the Crystal Reports SDK on the individual workstation, instead of sending report jobs to a central server (Bunnahabhain) running Crystal Server. Crystal Server then uses Report Commander to create the PDF.


Since this is caused by missing rows in the reportparameter table, re-running the adder scripts will generally fix the issue.
=== What is handled by Crystal Server and what is handled by Report Queue? ===


If it doesn't, the adder script could be out of date or otherwise missing parameters.
Report Queue and Crystal Server are two separate systems that do not interact, so it's important to understand the boundaries between them.  


==== Parameter not found in report: <parametername> ====
Crystal Server generates PDFs that can be viewed in a web browser. Crystal Server only generates the PDF, but it's typically displayed in either the "Report Viewer" screen, or in the "Send Report" modal in the application that requested it.


This means that a report was passed a parameter it doesn't expect.
Report Queue handles emailing and printing of reports. In the web, you can print/email using Report Queue by selecting "Printer" or "Email" in the "Send Report" modal.


===== Solution =====
=== Can Crystal Server (web report viewer) generate PDFs of different sizes? ===


Make sure the report is up to date
Unfortunately not. Report PDFs created by Crystal Server are always letter size. Note that this only applies to report previews; if the customer has a Report Queue instance they can email or print a report of a different size that way.


==== (I can't remember the error message) ====
=== Why can't web work the same way as desktop? ===


Missing / invalid ODBC configuration. I think this presents as "could not connect to the database" or something to that effect.
Chromium, Presage Web, and Enterprise Web run inside of a web browser, and can therefore be used on multiple operating systems without installing anything. Crystal Reports SDK is Windows-only and requires installation. Therefore, we need a central server to generate the pdf and send it back to the web browser (with some extra steps in between)


===== Solution =====
=== Why does this report run on desktop, but not on web? ===


Brian can make sure the ODBC connection is valid, and give Charles the name to check that the ODBC connection name in the Crystal Server config is correct.
As outlined above, web and desktop have entirely different stacks for running crystal reports. In short, web uses Report Commander instead of the Crystal SDK. I don't know exactly how the official Crystal SDK works, but it seems to be more tolerant to being passed extra parameters, or missing parameters. Report Commander is pickier so it will throw when you give it an extra parameter not found in the report, or if you are missing a required parameter value. As a result, basically every error in this Wiki article is web-exclusive.


==== Invalid Value for <parameter> ====
=== Why aren't reports updated automatically in the web? ===


Report Commander received an invalid value for the specified parameter
Report updates were historically done by ITrack/Presage desktop, and there is currently no system for automatically updating reports without using desktop. One is in progress, but as of 2/4/2026, it is not ready for primetime.


=== Invalid Session ===
=== Why do I sometimes get "504 Gateway Timeout" when running a report in web? ===


This error is caused by the Crystal Server failing to verify the session token it was passed.  
As outlined above, there are multiple web servers involved in the process of generating a PDF from a Crystal Report in the web, and each one of them has their own server-level timeouts. The web server(s) connecting you to the application API (Chromium, Presage API, EE API) might time you out, and so might the web server connecting the application API to the Crystal Server.


==== Solution ====
The NGINX default timeout is 60 seconds, and it's expected that some reports will take longer than this. More on this later.


Most likely, if logging out and back in doesn't fix it, this means that the Crystal Server configuration is either missing, or configured with a different database host URL than the API. Charles can check the logs to double check, as well as update the config file. Brian can then restart the Crystal Server service to load the updated configuration.
Presage Web has set its internal NGINX <code>proxy_read_timeout</code> for <code>/graphql</code> to <code>300s</code>, meaning that any and all requests to the API will time out at 300s instead of the default of 60s. However, the VM-level NGINX also defaults <code>proxy_read_timeout</code> to <code>60s</code> and if that's not raised, then the VM-level NGINX will time out before the Web-level NGINX hits its timeout.


=== Invalid Report ===
Currently EE API uses the default <code>proxy_read_timeout</code> of <code>60s</code>.


The Crystal Server failed to find the report with the specified name/type. Or, the report is missing its corresponding <code>file</code> data.
I do not know what timeouts are at play for Chromium since it uses a socket server instead of a GraphQL server like Presage Web and EEW do.


=== The file or directory is corrupted and unreadable ===
Requests to Crystal Server on Bunnahabhain currently time out at 4m, so provided that the web client -> API timeout is longer than that (such as 5m), the API can catch the timeout error and return a more user-readable error to the client as is the case in Presage API.


Once or twice the cached .rpt file on Bunnahabhain was corrupted or something. We fixed it by reuploading the report to the customer's db and deleting the cached .rpt file from <code>\\192.168.5.18\Node\crystal-reports-server\cache</code>
==== Can we make the timeouts longer? ====


It's possible it was because the D drive was failing. Cache has been moved to M:\report_cache
Well, it's complicated. Currently the only timeouts at play are the VM-level and Web-container-level NGINX timeouts. So while those ''can'' be raised, it will be raised for ''every request to the API'', including requests that we'd prefer to time out at 60 seconds. If that's an acceptable tradeoff for your product, then the NGINX timeout can be raised ''for all GraphQL requests''.


=== Other Errors ===
We could come up with a way to time out non-report GraphQL requests early, whether that's by creating a custom plugin for our GraphQL client (Houdini) or by adding something to the API servers that can know to time some requests out at 300s and some at 60s, but we haven't done anything like that yet.
 
==== Why does it sometimes take a few minutes for a timed-out report preview to show in the "History" tab? ====
 
"Web Preview" jobs are only logged to the <code>reportqueue</code> table after the API receives a response from Crystal Server. If your preview timed out at 60 seconds, then the request from the web client to the API likely timed out, meaning the API is still waiting for a response from Crystal Server. Since the API is still waiting, it will either create the <code>reportqueue</code> row after the report finishes, or once the request from API -> Crystal Server times out, whichever happens first. And when the request from the client -> API times out, the API doesn't know about it - so it's possible for the <code>reportqueue</code> row to report no errors if the report finishes running before the request from API -> Crystal Server times out. Timeouts like this will probably come with the error <code>Failed to fetch: server returned invalid response with error 504: Gateway Time-out</code> in EEW/Presage Web, as that's what's returned from our GraphQL client when it hits an NGINX timeout.
 
If the request from the API -> Crystal Server is the first to time out, the API will catch the timeout error and return a GraphQL error to the client. In this case, since the error was caught by the API, it will immediately log to <code>reportqueue</code>.
 
=== How is Report Queue, the Python application, involved in this? ===
 
It's not. Crystal Server and Report Queue are completely separate applications. Crystal Server only generates PDF previews. Report Queue handles printing and emailing reports. Crystal Server is written in Node.js, Report Queue is written in Python. Their main similarity is that they both invoke Report Commander to generate the PDF file, and log to the <code>reportqueue</code> table.
 
=== Why do Presage customers need set up manually? ===
 
Presage customers (generally) are on their own VM, and therefore database server. Therefore, they need their own entries in the Crystal Server config file.
 
Theoretically SMB customers, since they're on the same server, could share a config, but that hasn't been explored as of 2/4/2026.
 
=== Why do Enterprise customers need set up manually? ===
 
Enterprise customers are generally on their own VM or server. Additionally, EE customers might not want to use our central server, and might want to host their own. Therefore, they need their own entries in the Crystal Server config file, or their own Crystal Server instance entirely.
 
=== Why don't Chromium customers need to be set up manually? ===
 
Since Chromium users are on one of three servers, (except for dev, demo, etc.) all Chromium instances can just use the config for their regional server


<code>Error: WARNING: MYSQL_OPT_RECONNECT is deprecated and will be removed in a future version.</code> - Disable "Auto Reconnect" on ODBC. Presents as "Unkown Error" or "Internal Server Error" in the UI
== Common Errors (Table Mode) ==


== Common Errors (Table Mode)==
This table will hold the answers to (probably) any error you will encounter running reports in Presage Web


{| class="wikitable" style=""
{| class="wikitable" style=""
Line 76: Line 110:
| Invalid Session. Try logging out and logging back in. || This means that the report server was not able to verify your session. Either your session has expired, or the Crystal Server is not configured for that database. The most likely cause of this is, if logging out and back in doesn't fix it, is that the (generally Presage) customer hasn't been set up on the Crystal Server, or some configuration has changed. || If the config for that customer is missing, then add it matching the template. If it is present, make sure that the Crystal Server and Chromium/Presage API are configured with the same DB URL. Otherwise, check the ODBC connection and DB credentials. Charles can check the logs to double check the URLs are good, as well as update the config file. Brian can then restart the Crystal Server service to load the updated configuration.
| Invalid Session. Try logging out and logging back in. || This means that the report server was not able to verify your session. Either your session has expired, or the Crystal Server is not configured for that database. The most likely cause of this is, if logging out and back in doesn't fix it, is that the (generally Presage) customer hasn't been set up on the Crystal Server, or some configuration has changed. || If the config for that customer is missing, then add it matching the template. If it is present, make sure that the Crystal Server and Chromium/Presage API are configured with the same DB URL. Otherwise, check the ODBC connection and DB credentials. Charles can check the logs to double check the URLs are good, as well as update the config file. Brian can then restart the Crystal Server service to load the updated configuration.
|-
|-
| rowspan="4" |Error running report. Double check the report parameters and try again. || This means that Report Commander did not receive the correct amount of parameters for the report. Often times, the report will run fine on desktop, because the Crystal SDK can "fill in the gaps" or ignore extra parameters, while the web Report Viewer cannot, and needs a row in reportparameter for every parameter. Check the <code>Report Viewer > History</code> tab for more error details || Generally, update the report and re-run adders, but '''See Below''' for more details, and check <code>Report Viewer > History</code> for more parameter and error details. If updating the report and adder doesn't fix it, it's possible that they are out of date and need fixed.
| rowspan="5" |Error running report. Double check the report parameters and try again. || This means that Report Commander did not receive the correct amount of parameters for the report. Often times, the report will run fine on desktop, because the Crystal SDK can "fill in the gaps" or ignore extra parameters, while the web Report Viewer cannot, and needs a row in reportparameter for every parameter. Check the <code>Report Viewer > History</code> tab for more error details || Generally, update the report and re-run adders, but '''See Below''' for more details, and check <code>Report Viewer > History</code> for more parameter and error details. If updating the report and adder doesn't fix it, it's possible that they are out of date and need fixed.
|-
|-
| '''"Invalid value for <parameter>"''' means Report Commander received an invalid value for the listed parameter. Usually this just means you forgot to fill a parameter out, but could be caused by by an outdated report / adders. || Make sure all parameters are filled out.
| '''"Invalid value for <parameter>"''' means Report Commander received an invalid value for the listed parameter. Usually this just means you forgot to fill a parameter out, but could be caused by by an outdated report / adders. || Make sure all parameters are filled out.
Line 84: Line 118:
| '''"Missing parameter values"''' means that the report was not passed all expected parameters. Normally, this is because a parameter was added to the report, and the adders are out of date. || Re-run adders.
| '''"Missing parameter values"''' means that the report was not passed all expected parameters. Normally, this is because a parameter was added to the report, and the adders are out of date. || Re-run adders.
|-
|-
|| (I can't remember the error message) || Missing / invalid ODBC configuration. I think this presents as "could not connect to the database" or something to that effect. || Brian can make sure the ODBC connection is valid, and give Charles the name to check that the ODBC connection name in the Crystal Server config is correct.
| '''"The types of the parameter field and parameter field current values are not compatible"''' means that Crystal was passed a parameter value of the wrong type for that parameter. For example, a string instead of a number || Make sure ITrack is sending parameters of the type the report expects to receive
|-
|| (I can't remember the error message) || Missing / invalid ODBC configuration. I think this presents as "could not connect to the database" or something to that effect. Sometimes it'll give you a "database vendor code" just like ITrack desktop. || Depending on the error code, Brian can make sure the ODBC connection is valid, and give Charles the name to check that the ODBC connection name in the Crystal Server config is correct. But some error codes like 1064 are unrelated to the odbc setup
|-
|-
|| Invalid Report || The Crystal Server failed to find the report with the specified name/type. || Make sure the report exists in the customer database with the given name and type, and a valid <code>report.fileid</code>. In Presage, there used to be a bug where running reports with a non-English language selected would fail with this error.
|| "Invalid Report" or "No report found of type <type> and name <name>" || The Crystal Server failed to find the report with the specified name/type. || Make sure the report exists in the customer database with the given name and type, and a valid <code>report.fileid</code>. In Presage, there used to be a bug where running reports with a non-English language selected would fail with this error.
|-
|-
|| The file or directory is corrupted and unreadable || This would come up every so often because the D drive on Bunnahabhain was failing. It shouldn't happen anymore. || It shouldn't happen again, but if it does, delete the cached report file from <code>M:\report_cache</code> on Bunnahabhain. Maybe reupload the report if it persists after that.
|| The file or directory is corrupted and unreadable || This would come up every so often because the D drive on Bunnahabhain was failing. It shouldn't happen anymore. || It shouldn't happen again, but if it does, delete the cached report file from <code>M:\report_cache</code> on Bunnahabhain. Maybe reupload the report if it persists after that.
|-
|| Database logon failed || ODBC could not connect to the database || Ask Brian (or maybe someone else from @Systems) to double check the ODBC connection on Bunnahabhain for that customer
|-
|| <code>Database Vendor Code (code)</code> || There was some MySQL error. Look up the error code. || Might depend on the error code, but it's probably because of a bad query in the report. Reupload report. If some parameters are missing or blank, there could have been an issue running a report parameter query, and omitting those parameters could have caused a syntax error (1064)
|-
|| <code>Internal Server Error</code> || Either you're on a version of EEW that doesn't forward the error to the client properly, or you encountered an error that is not properly handled by Crystal Server || Check Report Viewer > History to see the actual error, or if that fails, the Crystal Server logs.
|}
|}
=== Other Errors ===
<code>Error: WARNING: MYSQL_OPT_RECONNECT is deprecated and will be removed in a future version.</code> - Disable "Auto Reconnect" on ODBC. Presents as "Unkown Error" or "Internal Server Error" in the UI


== Logs ==
== Logs ==
Line 130: Line 176:


<code>\\192.168.5.18\Node\crystal-reports-server\config.json</code>
<code>\\192.168.5.18\Node\crystal-reports-server\config.json</code>
Generally, you just need to set the host, user, password, and odbc data sources for a new connection. However, host MUST be unique, and MUST match the ITrack/Presage server config, as that's what's used to look up the rest of the connection info. Most of the time you can just add another entry to the JSON, like so
<code><pre>{
"host": "HOST",
"user": "USER",
"password": "PASSWORD",
"odbcDataSource": "ODBC DATA SOURCE NAME"
}</pre></code>
In some cases you might also need to set the <code>caPath</code>, <code>certPath</code>, <code>keyPath</code> properties depending on the SSL config. See other configured hosts for examples.
After adding to the JSON, restart the <code>CrystalServer</code> service to apply any changes. See below for more product-specific details.


=== Chromium ===
=== Chromium ===
Line 144: Line 204:


Since the setup for SMB clients is slightly different, the <code>MYSQL_HOST</code> is an "internal" IP, but we need an external host that matches what the Crystal Server knows. To get around this, specify this ENV variable:<code>EXTERNAL_DB_HOST: <customername>-database.presageanalytics.com</code>. Make sure the URL matches the one in the Crystal Server config. Apparently, SMB DB URLs will always have <code>-database</code> in them since the SMB docker containers don't run on the same iron as MySQL.
Since the setup for SMB clients is slightly different, the <code>MYSQL_HOST</code> is an "internal" IP, but we need an external host that matches what the Crystal Server knows. To get around this, specify this ENV variable:<code>EXTERNAL_DB_HOST: <customername>-database.presageanalytics.com</code>. Make sure the URL matches the one in the Crystal Server config. Apparently, SMB DB URLs will always have <code>-database</code> in them since the SMB docker containers don't run on the same iron as MySQL.
As of 02/03/2025, there's also Bartlett, which had some issues setting it up related to SSL. Brian fixed it, I'm not sure what he did. I think they're also set up slightly differently than Culligan GI


==== Self-Hosted ====
==== Self-Hosted ====
Line 149: Line 211:
If they're okay hitting our Crystal Server, we just need to make sure that their database can be reached on Bunnahabhain, then the setup is the same as a hosted yard.  
If they're okay hitting our Crystal Server, we just need to make sure that their database can be reached on Bunnahabhain, then the setup is the same as a hosted yard.  


If not, we'll have to deploy it to a Windows server they control, and set the <code>REPORT_SERVER_URI</code> ENV variable in the API to the proper URI
If not, we'll have to deploy it to a Windows server they control, and set the <code>REPORT_SERVER_URI</code> ENV variable in the API to the proper URI. Presage API will have to be able to reach <code><The Server URL>/process_report</code> in order to generate the reports


=== Enterprise Web/API ===
=== Enterprise Web/API ===


TBD! But we probably aren't going to have anyone configured with a print server URL by default, since each customer will have to be set up manually. In theory if they open a port to us, they can be configured to use our Crystal Server, but they might not want to. In that case, we'll have to deploy Crystal Server to a Windows server that they control.
If we host the customer, we should just set them up on our Crystal Server. Follow the general steps for configuring them in the Crystal Server config.json, then set some ENV variables in Portainer:
 
* <code>REPORT_SERVER_URI: http://print.itrackchromium.com</code>
* <code>EXTERNAL_DB_HOST: example-url.itrackenterprise.com</code>
 
WG, UT&W, & QBT are currently (07/08/25) the only EE customers with the web report viewer on, and they also had to have the caPath set in the crystal server config to the old/not-2024 ca cert. Not sure if that'll be true for other EE customers, but it was for them.
 
If they're self hosted, and don't want to use our Crystal Server, follow the steps under "Deployment", then set the above ENV variables to the proper values for their setup.
 
=== Updating a Client to MySQL 8 ===
 
When a client's database is updated to MySQL 8, the MySQL connector 5.3 will no longer work. Update their ODBC to use the MySQL 8.0 Unicode driver, and turn off "Enable automatic reconnect"


== Updating ==
== Updating ==
Line 171: Line 244:
* Get the latest EXE or build a new one from https://github.com/ISoft-Data-Systems/crystal-reports-server and replace the old EXE from the installer
* Get the latest EXE or build a new one from https://github.com/ISoft-Data-Systems/crystal-reports-server and replace the old EXE from the installer
* Restart the CrystalServer service
* Restart the CrystalServer service
* Make sure the service is reachable by the Presage API
* Make sure the service is reachable from wherever the Presage API is running
* At this point, they should be able to make a request to <code>serveruri</code>/process_report and get a report back.
* At this point, they should be able to make a request to <code>serveruri</code>/process_report and get a report back.



Latest revision as of 15:45, 13 May 2026

This article applies to Presage Web and ITrack Chromium. The web Report Viewer will give a general error, error details are logged to the reportqueue table and can be viewed in the "History" (web) or "Print Queue" (desktop) tab of the Report Viewer screen.

Terms

  • Crystal Server - the Node.JS application that uses Report Commander to generate the report PDF. Runs on Bunnahabhain. This application is not the same as Report Queue.
  • Report Commander - command line application used to generate report PDFs by the Crystal Server (and Report Queue)
  • Report Queue - python application that reads from reportqueue table to send emails and print to a printer. Report Queue is separate from Crystal Server, and the two systems do not interact.
  • reportqueue - a table in the database that logs report runs.
  • reportparameter - a table in the database that associates parameters to reports

FAQ

How does the web report viewer work?

Since we can't run crystal reports directly in the browser, we need to run them on a central server and send them back to the web browser. There are multiple servers involved in this process, which I'll outline below

  • The report and parameter list are loaded from the application's API (Chromium, Presage API, EE API)
  • The user selects a report, fills out parameters, and clicks "Preview"
  • A request is sent to the application backend (Chromium, Presage API, EE API)
  • Application backend sends a request to Crystal Server, running on Bunnahabhain, or a customer server if relevant. This requests includes details of the report to run, which database to run it on, and a valid session token for that database.
  • Bunnahabhain takes this request, and attempts to validate the given session token in the given database. If this fails, such as if the token is invalid or it can't connect to the database, an "Invalid Session" error is thrown.
  • After the session is validated, Crystal Server will download the report file from the customer's database, and run default parameter queries. The report is saved to the "cache directory" specified in the config, with the file's hash as the file name.
  • Then, Crystal Server creates a command line string to run Report Commander for the given report and parameters
  • Report Commander is then invoked to generate the PDF, connecting to the database with ODBC. The PDF is saved to a folder in the Crystal Server's "cache directory". If Report Commander throws an error, it is forwarded to the application API (Chromium, Presage API, EE API), which saves it to the reportqueue table and forwards that error to the client, where it is displayed.
  • If it succeeds, the report file is base64 encoded and sent back to the application API (Chromium, Presage API, EE API), along with the time it took to execute the report.
  • The application API receives the request, saves the details to reportqueue/reportqueueparameter, and returns the base64 encoded PDF to the client
  • The client receives the response from its backend, and displays the base64 encoded PDF in the browser using an <object/> tag

How is that different from desktop?

ITrack desktop talks directly to the Crystal Reports SDK on the individual workstation, instead of sending report jobs to a central server (Bunnahabhain) running Crystal Server. Crystal Server then uses Report Commander to create the PDF.

What is handled by Crystal Server and what is handled by Report Queue?

Report Queue and Crystal Server are two separate systems that do not interact, so it's important to understand the boundaries between them.

Crystal Server generates PDFs that can be viewed in a web browser. Crystal Server only generates the PDF, but it's typically displayed in either the "Report Viewer" screen, or in the "Send Report" modal in the application that requested it.

Report Queue handles emailing and printing of reports. In the web, you can print/email using Report Queue by selecting "Printer" or "Email" in the "Send Report" modal.

Can Crystal Server (web report viewer) generate PDFs of different sizes?

Unfortunately not. Report PDFs created by Crystal Server are always letter size. Note that this only applies to report previews; if the customer has a Report Queue instance they can email or print a report of a different size that way.

Why can't web work the same way as desktop?

Chromium, Presage Web, and Enterprise Web run inside of a web browser, and can therefore be used on multiple operating systems without installing anything. Crystal Reports SDK is Windows-only and requires installation. Therefore, we need a central server to generate the pdf and send it back to the web browser (with some extra steps in between)

Why does this report run on desktop, but not on web?

As outlined above, web and desktop have entirely different stacks for running crystal reports. In short, web uses Report Commander instead of the Crystal SDK. I don't know exactly how the official Crystal SDK works, but it seems to be more tolerant to being passed extra parameters, or missing parameters. Report Commander is pickier so it will throw when you give it an extra parameter not found in the report, or if you are missing a required parameter value. As a result, basically every error in this Wiki article is web-exclusive.

Why aren't reports updated automatically in the web?

Report updates were historically done by ITrack/Presage desktop, and there is currently no system for automatically updating reports without using desktop. One is in progress, but as of 2/4/2026, it is not ready for primetime.

Why do I sometimes get "504 Gateway Timeout" when running a report in web?

As outlined above, there are multiple web servers involved in the process of generating a PDF from a Crystal Report in the web, and each one of them has their own server-level timeouts. The web server(s) connecting you to the application API (Chromium, Presage API, EE API) might time you out, and so might the web server connecting the application API to the Crystal Server.

The NGINX default timeout is 60 seconds, and it's expected that some reports will take longer than this. More on this later.

Presage Web has set its internal NGINX proxy_read_timeout for /graphql to 300s, meaning that any and all requests to the API will time out at 300s instead of the default of 60s. However, the VM-level NGINX also defaults proxy_read_timeout to 60s and if that's not raised, then the VM-level NGINX will time out before the Web-level NGINX hits its timeout.

Currently EE API uses the default proxy_read_timeout of 60s.

I do not know what timeouts are at play for Chromium since it uses a socket server instead of a GraphQL server like Presage Web and EEW do.

Requests to Crystal Server on Bunnahabhain currently time out at 4m, so provided that the web client -> API timeout is longer than that (such as 5m), the API can catch the timeout error and return a more user-readable error to the client as is the case in Presage API.

Can we make the timeouts longer?

Well, it's complicated. Currently the only timeouts at play are the VM-level and Web-container-level NGINX timeouts. So while those can be raised, it will be raised for every request to the API, including requests that we'd prefer to time out at 60 seconds. If that's an acceptable tradeoff for your product, then the NGINX timeout can be raised for all GraphQL requests.

We could come up with a way to time out non-report GraphQL requests early, whether that's by creating a custom plugin for our GraphQL client (Houdini) or by adding something to the API servers that can know to time some requests out at 300s and some at 60s, but we haven't done anything like that yet.

Why does it sometimes take a few minutes for a timed-out report preview to show in the "History" tab?

"Web Preview" jobs are only logged to the reportqueue table after the API receives a response from Crystal Server. If your preview timed out at 60 seconds, then the request from the web client to the API likely timed out, meaning the API is still waiting for a response from Crystal Server. Since the API is still waiting, it will either create the reportqueue row after the report finishes, or once the request from API -> Crystal Server times out, whichever happens first. And when the request from the client -> API times out, the API doesn't know about it - so it's possible for the reportqueue row to report no errors if the report finishes running before the request from API -> Crystal Server times out. Timeouts like this will probably come with the error Failed to fetch: server returned invalid response with error 504: Gateway Time-out in EEW/Presage Web, as that's what's returned from our GraphQL client when it hits an NGINX timeout.

If the request from the API -> Crystal Server is the first to time out, the API will catch the timeout error and return a GraphQL error to the client. In this case, since the error was caught by the API, it will immediately log to reportqueue.

How is Report Queue, the Python application, involved in this?

It's not. Crystal Server and Report Queue are completely separate applications. Crystal Server only generates PDF previews. Report Queue handles printing and emailing reports. Crystal Server is written in Node.js, Report Queue is written in Python. Their main similarity is that they both invoke Report Commander to generate the PDF file, and log to the reportqueue table.

Why do Presage customers need set up manually?

Presage customers (generally) are on their own VM, and therefore database server. Therefore, they need their own entries in the Crystal Server config file.

Theoretically SMB customers, since they're on the same server, could share a config, but that hasn't been explored as of 2/4/2026.

Why do Enterprise customers need set up manually?

Enterprise customers are generally on their own VM or server. Additionally, EE customers might not want to use our central server, and might want to host their own. Therefore, they need their own entries in the Crystal Server config file, or their own Crystal Server instance entirely.

Why don't Chromium customers need to be set up manually?

Since Chromium users are on one of three servers, (except for dev, demo, etc.) all Chromium instances can just use the config for their regional server

Common Errors (Table Mode)

This table will hold the answers to (probably) any error you will encounter running reports in Presage Web

Common Errors
Error Description How to Fix
Invalid Session. Try logging out and logging back in. This means that the report server was not able to verify your session. Either your session has expired, or the Crystal Server is not configured for that database. The most likely cause of this is, if logging out and back in doesn't fix it, is that the (generally Presage) customer hasn't been set up on the Crystal Server, or some configuration has changed. If the config for that customer is missing, then add it matching the template. If it is present, make sure that the Crystal Server and Chromium/Presage API are configured with the same DB URL. Otherwise, check the ODBC connection and DB credentials. Charles can check the logs to double check the URLs are good, as well as update the config file. Brian can then restart the Crystal Server service to load the updated configuration.
Error running report. Double check the report parameters and try again. This means that Report Commander did not receive the correct amount of parameters for the report. Often times, the report will run fine on desktop, because the Crystal SDK can "fill in the gaps" or ignore extra parameters, while the web Report Viewer cannot, and needs a row in reportparameter for every parameter. Check the Report Viewer > History tab for more error details Generally, update the report and re-run adders, but See Below for more details, and check Report Viewer > History for more parameter and error details. If updating the report and adder doesn't fix it, it's possible that they are out of date and need fixed.
"Invalid value for <parameter>" means Report Commander received an invalid value for the listed parameter. Usually this just means you forgot to fill a parameter out, but could be caused by by an outdated report / adders. Make sure all parameters are filled out.
"Parameter not found in report: <parameter>" means that a parameter was passed to the report that the report doesn't expect. If caused by an out-of-date report (more common), update the report. If caused by out-of-date adders, re-run adders.
"Missing parameter values" means that the report was not passed all expected parameters. Normally, this is because a parameter was added to the report, and the adders are out of date. Re-run adders.
"The types of the parameter field and parameter field current values are not compatible" means that Crystal was passed a parameter value of the wrong type for that parameter. For example, a string instead of a number Make sure ITrack is sending parameters of the type the report expects to receive
(I can't remember the error message) Missing / invalid ODBC configuration. I think this presents as "could not connect to the database" or something to that effect. Sometimes it'll give you a "database vendor code" just like ITrack desktop. Depending on the error code, Brian can make sure the ODBC connection is valid, and give Charles the name to check that the ODBC connection name in the Crystal Server config is correct. But some error codes like 1064 are unrelated to the odbc setup
"Invalid Report" or "No report found of type <type> and name <name>" The Crystal Server failed to find the report with the specified name/type. Make sure the report exists in the customer database with the given name and type, and a valid report.fileid. In Presage, there used to be a bug where running reports with a non-English language selected would fail with this error.
The file or directory is corrupted and unreadable This would come up every so often because the D drive on Bunnahabhain was failing. It shouldn't happen anymore. It shouldn't happen again, but if it does, delete the cached report file from M:\report_cache on Bunnahabhain. Maybe reupload the report if it persists after that.
Database logon failed ODBC could not connect to the database Ask Brian (or maybe someone else from @Systems) to double check the ODBC connection on Bunnahabhain for that customer
Database Vendor Code (code) There was some MySQL error. Look up the error code. Might depend on the error code, but it's probably because of a bad query in the report. Reupload report. If some parameters are missing or blank, there could have been an issue running a report parameter query, and omitting those parameters could have caused a syntax error (1064)
Internal Server Error Either you're on a version of EEW that doesn't forward the error to the client properly, or you encountered an error that is not properly handled by Crystal Server Check Report Viewer > History to see the actual error, or if that fails, the Crystal Server logs.

Other Errors

Error: WARNING: MYSQL_OPT_RECONNECT is deprecated and will be removed in a future version. - Disable "Auto Reconnect" on ODBC. Presents as "Unkown Error" or "Internal Server Error" in the UI

Logs

The log file lives at:

\\192.168.5.18\Node\crystal-reports-server\crystalserverservice.log

A normal log entry for a report job looks like this:

Connection created for 'hosteddb-southeast.isoftdata.com.373487'
args [
  '-report="D:\\Node\\crystal-reports-server\\cache\\A95AC82D42C7A2A9AFF9F720DA5F3159.rpt"',
  '-login!={server:reporting_hosted_southeast}{database:373487}',
  '-exportfile="D:\\Node\\crystal-reports-server\\cache\\output\\default_invoice_2024-12-03T19-20-25.872Z.pdf"',
  '-exportformat="PDF"',
  '-namedparameters invoicenum="5150"'
]
Destroying connection for 'hosteddb-southeast.isoftdata.com.373487'

If you see a message like this, then the Crystal Server (not ODBC) failed to connect to the database, and there will probably be a logged request body right below it. The logged request body should have the db host sent from the application, which can be compared to the valid hosts in the config file

Destroying connection for 'iceriver.presageanalytics.com.UNKNOWN DATABASE'

The most common errors you'll see start like this and will show the command used to run Report Commander as well as a more-detailed error message in a mess of JSON.

ReportError: A Report Commander error has occurred

Configuration

This will go over how to configure a customer on the Crystal Server, not so much how to deploy and configure a new Crystal Server.

The config file lives at:

\\192.168.5.18\Node\crystal-reports-server\config.json

Generally, you just need to set the host, user, password, and odbc data sources for a new connection. However, host MUST be unique, and MUST match the ITrack/Presage server config, as that's what's used to look up the rest of the connection info. Most of the time you can just add another entry to the JSON, like so

{
	"host": "HOST",
	"user": "USER",
	"password": "PASSWORD",
	"odbcDataSource": "ODBC DATA SOURCE NAME"
}


In some cases you might also need to set the caPath, certPath, keyPath properties depending on the SSL config. See other configured hosts for examples.

After adding to the JSON, restart the CrystalServer service to apply any changes. See below for more product-specific details.

Chromium

Does not have to be configured per-customer. One config per VM. The users have more security and so they use more of the SSL options than other users

Presage Web/API

REPORT_SERVER_URI specifies the report server URI used by the server, and MYSQL_HOST specifies the DB host. EXTERNAL_DB_HOST will be sent to the Crystal Server instead of MYSQL_HOST, if specified. Either MYSQL_HOST or EXTERNAL_DB_HOST MUST match the host in the Crystal Server config file or it will not work!

SMB

Currently (12/04/2024), Culligan GI is the only Presage SMB customer, and was configured individually. Maybe in the future, Presage SMB will work like Chromium and just have one config per VM, but that's not currently the case.

Since the setup for SMB clients is slightly different, the MYSQL_HOST is an "internal" IP, but we need an external host that matches what the Crystal Server knows. To get around this, specify this ENV variable:EXTERNAL_DB_HOST: <customername>-database.presageanalytics.com. Make sure the URL matches the one in the Crystal Server config. Apparently, SMB DB URLs will always have -database in them since the SMB docker containers don't run on the same iron as MySQL.

As of 02/03/2025, there's also Bartlett, which had some issues setting it up related to SSL. Brian fixed it, I'm not sure what he did. I think they're also set up slightly differently than Culligan GI

Self-Hosted

If they're okay hitting our Crystal Server, we just need to make sure that their database can be reached on Bunnahabhain, then the setup is the same as a hosted yard.

If not, we'll have to deploy it to a Windows server they control, and set the REPORT_SERVER_URI ENV variable in the API to the proper URI. Presage API will have to be able to reach <The Server URL>/process_report in order to generate the reports

Enterprise Web/API

If we host the customer, we should just set them up on our Crystal Server. Follow the general steps for configuring them in the Crystal Server config.json, then set some ENV variables in Portainer:

WG, UT&W, & QBT are currently (07/08/25) the only EE customers with the web report viewer on, and they also had to have the caPath set in the crystal server config to the old/not-2024 ca cert. Not sure if that'll be true for other EE customers, but it was for them.

If they're self hosted, and don't want to use our Crystal Server, follow the steps under "Deployment", then set the above ENV variables to the proper values for their setup.

Updating a Client to MySQL 8

When a client's database is updated to MySQL 8, the MySQL connector 5.3 will no longer work. Update their ODBC to use the MySQL 8.0 Unicode driver, and turn off "Enable automatic reconnect"

Updating

Not 100% sure since it's been awhile, but I'm pretty sure the process is basically: 1. Build the Crystal Server to an exe again 2. Replace the old exe on BH 3. Restart CrystalServer service

Deployment

For 99% of customers, this section will not apply. But in the event that a self-hosted customer wants to host their own Crystal Server, this is probably how.

  • Locate a Windows Server
  • Install Report Commander on it
  • Run CrystalServerSetup.exe from dl.isoftdata.com, I think this sets up the service to make it run in the background and on startup?
  • Get the latest EXE or build a new one from https://github.com/ISoft-Data-Systems/crystal-reports-server and replace the old EXE from the installer
  • Restart the CrystalServer service
  • Make sure the service is reachable from wherever the Presage API is running
  • At this point, they should be able to make a request to serveruri/process_report and get a report back.

Misc / Notes

Housby has Crystal Server deployed to generate invoice PDFs for an ecommerce integration. They're using a version before we compiled it to an exe, so if they ever run into bugs or need an update it will be a little different