@@ -188,6 +188,11 @@ function tide_media_preprocess_file_link(&$variables) {
188188 }
189189
190190 $description = $variables['description'];
191+ // Fallback to filename when description is NULL to prevent TypeError
192+ // in Html::escape() via FormattableMarkup.
193+ if (empty($description)) {
194+ $description = $file->getFilename();
195+ }
191196 $file_size = ByteSizeMarkup::create($file->getSize());
192197
193198 $mime_type = $file->getMimeType();
@@ -291,11 +296,17 @@ function tide_media_entity_base_field_info_alter(&$fields, EntityTypeInterface $
291296function tide_media_preprocess_image(&$variables) {
292297 // Return the absolute URL for images.
293298 if (!empty($variables['uri'])) {
294- $config = \Drupal::config('tide_media.settings');
295- if ($config->get('file_absolute_url')) {
296- $variables['attributes']['src'] = \Drupal::service('file_url_generator')->generateAbsoluteString($variables['uri']);
297- if ($config->get('force_https')) {
298- $variables['attributes']['src'] = str_replace('http://', 'https://', $variables['attributes']['src']);
299+ $uri = $variables['uri'];
300+ // Only process stream wrapper URIs (e.g. public://, private://).
301+ // Skip URIs that are already full URLs (e.g. from focal_point preview)
302+ // to avoid double-processing which breaks filenames with spaces.
303+ if (strpos($uri, '://') !== FALSE && !preg_match('#^https?://#', $uri)) {
304+ $config = \Drupal::config('tide_media.settings');
305+ if ($config->get('file_absolute_url')) {
306+ $variables['attributes']['src'] = \Drupal::service('file_url_generator')->generateAbsoluteString($uri);
307+ if ($config->get('force_https')) {
308+ $variables['attributes']['src'] = str_replace('http://', 'https://', $variables['attributes']['src']);
309+ }
299310 }
300311 }
301312 }
0 commit comments