Error 500 in Heroku production pipeline involving static files and DEBUG set to False in settings.py

I’m trying to deploy my Django project to Heroku. In the staging pipeline environment, it runs and I can access my site. But when I promote the tested changes on Heroku to prod, the browser shows an “Internal Server Error”. When I run: $ heroku logs --tail, the trace back reveals a 500 error. In greater detail, the trace back indicates: “ValueError: Missing staticfiles manifest entry for ‘books/Blair_2010.pdf’”. That’s the error message.

For context, books is a directory carrying a very small collection of .pdf’s which are binary static files.

In the Heroku administrative dashboard, when I switch the DEBUG flag to False, Django serves my web pages no problem. When I click a link with a hard coded reference to a static file, it loads. Static files are working. So I wonder if this points more towards the DEBUG configuration issue instead of a static file configuration issue.

Since it’s not a good idea to have DEBUG set to True in production, I am trying to get Django to serve my web pages successfully with DEBUG set to False before I begin adding any of my production blog content.

Quite a number of other Django users have encountered the same issue I have. It’s all over Stack Overflow. Here is someone who has a highly upvoted question who has basically the exact same issue I have:

I’ve tried substituting different static file variable configurations based on the answers recommended in that thread which hasn’t resolved my issue. I feel like I have tried everything. I am all out of ideas.

Based on my configuration files shared below, what might you people recommend I try next?

Here is the DEBUG declaration in my settings.py:

DEBUG = config('DEBUG', default=True, cast=bool)

(At the top of the settings.py file I have imported the config function from the decouple module.)

Inside the MIDDLEWARE variable, I have specified:

"whitenoise.middleware.WhiteNoiseMiddleware",

Here is the section in my settings.py where I declare my static files configuration variables:

STATIC_URL = '/staticfiles/'
STATICFILES_DIRS = [ os.path.join(BASE_DIR,'static') ]
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
# I got the below from:
# https://stackoverflow.com/questions/53859972/django-whitenoise-500-server-error-in-non-debug-mode
STATICFILES_STORAGE = "whitenoise.storage.CompressedStaticFilesStorage"

The above is what is currently deployed to both staging and prod pipelines. As I mentioned earlier, this configuration works with DEBUG set to True but not when set to False. Based on my rummaging around Stack Overflow, here are some additional variable declarations that I experimented with (but now currently have them commented out):

'''
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/
STATIC_URL = 'static/'
STATICFILES_DIRS = [
   BASE_DIR / "static",
]
STATIC_ROOT = BASE_DIR / "hypno_juicer/static"
'''
 
'''
STATIC_URL = "/static/"
STATICFILES_DIRS = [str(BASE_DIR.joinpath("hypno_juicer/static"))]
STATIC_ROOT = str(BASE_DIR.joinpath("static"))
'''
 
'''
Commented out this (Originally from John Elder):
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
Accoding to: https://stackoverflow.com/a/66661021/6095646
Trying this instead :
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
'''

Does collectstatic run as a part of your build process? You can check your build logs in your Heroku app under the Activity tab.

Thanks for your reply. I have two pipelines configured on Heroku- - staging and production. When I push to staging, I can watch the buildpack in my shell run which includes execution of collectstatic. I see it in the build logs. When I open the app (staging), everything loads, including the static files. No error. The site behaves as expected. But after promoting the staging slug to prod (exact replicas of each other), the live production server throws the 500 "ValueError: Missing staticfiles manifest entry ". The only differences between the two environments are the 6 unqiue config variables. If I switch the DEBUG value to True in prod, then that resolves the issue. But it’s really not best practices to have DEBUG set to True in prod. When switched back to False, the 500 error returns.

Does staging also throw the errors if DEBUG=False?

Try switching back to django.contrib.staticfiles.storage.StaticFilesStorage too. If it still says it doesn’t, exist, double check that the file is indeed in your static files and is committed to source control.

Thanks for the suggestion. I flipped with switch in staging. The staging app presents a 500 error as well.

I tried this too just now. I pushed to staging which re-compiled the slug which included collectstatic. The staging app loads and behaves as expected. But after promoting to prod, the prod app continues to show the 500.

For further insight, I thought it might be helpful to share my full settings.py. Here it is on GitHub: https://github.com/enoren5/hypno_juicer/blob/main/hypno_juicer/settings.py
And here is the parent repo: GitHub - enoren5/hypno_mixer: Using self-hypnosis for self-discipline

Are you sure that the file being referenced that’s causing the error exists in source control? I would have expected to find Blair_2010.pdf here.

Eureka! You have a good eye. Thanks for identifying the problem. I corrected the incorrectly named ebook from .pdf to .epub. After commiting the changes and promoting the latest staging to prod, now the production app works perfectly! The 500 error is gone.

I was skeptical at first with the subtlety you noticed because it’s not clear to me why Django would present a 500 error with an incorrectly referenced static file in my template with DEBUG set to False but not True. Do you know why this might be?

Anyways, thanks so much @CodenameTim for catching that in my source code!

The {% static %} tag hashes part of the file path when DEBUG=False. However, I suspected that the file may not exist given the original error message and the fact that you switched away from the manifest storage class. The next step would have been to ask what the latest error message was.

1 Like