Recently ran into this issue where a dataLayer was defined and showing in debug mode but GA would keep randomly sending out undefined as category/action/label values in GA - which was quite frustrating for the developer because the right details were indeed getting passed in DOM.
Something was going wrong between DOM and GA. Here's what I had going before seeking help in Google Tag Manager Product forum.
Define dataLayer event to pick up category/action/label [action and label parts of event were dynamic and captured from page interaction.
Create these dataLayer as unique category/action/variables for GTM to pick up the values.
Created a click based trigger where when the page interaction took place + category/action/label matched RegEx .* , an event fired.
GA event created with action and label fields being the dataLayer values while the trigger being in step#3.
As dumb as it sounds now, step#3 was the problem where category/action/label were created as an event and not just a click. Changing the trigger in step#3 from click based to Custom Event where the event = the name of the dataLayer event name [not category/action/label] plus changing the matches RegEx .* to does not contain 'undefined' makes sure that we have values in place.
Here's the link to Google Tag Manager Product Forum where I got help in fixing this.