Skip to main content
Printing can fail for various reasons. This guide shows you how to handle errors gracefully and troubleshoot common issues.

Using onPrintError callback

The onPrintError callback catches errors during printing:
<script setup>
import { ref } from 'vue'
import { usePrint } from 'vue-print-it'

const { print } = usePrint()
const errorMessage = ref('')

function handlePrint() {
  print('content', {
    onPrintError: (error: Error) => {
      console.error('Print error:', error)
      errorMessage.value = error.message
    }
  })
}
</script>

<template>
  <div>
    <button @click="handlePrint">Print</button>
    <p v-if="errorMessage" class="error">{{ errorMessage }}</p>
  </div>
</template>

Try-catch pattern

Wrap print calls in try-catch:
<script setup>
import { ref } from 'vue'
import { usePrint } from 'vue-print-it'

const { print } = usePrint()
const errorMessage = ref('')
const isPrinting = ref(false)

async function handlePrint() {
  isPrinting.value = true
  errorMessage.value = ''
  
  try {
    await print('content', {
      windowTitle: 'My Document'
    })
  } catch (error) {
    console.error('Failed to print:', error)
    errorMessage.value = 'Unable to print document. Please try again.'
  } finally {
    isPrinting.value = false
  }
}
</script>

Common errors

Element not found

This error occurs when the element ID or reference doesn’t exist:
<script setup>
import { usePrint } from 'vue-print-it'

const { print } = usePrint()

function handlePrint() {
  const elementId = 'my-content'
  
  // Check if element exists
  const element = document.getElementById(elementId)
  
  if (!element) {
    console.error(`Element with ID "${elementId}" not found`)
    return
  }
  
  print(elementId, {
    onPrintError: (error) => {
      if (error.message.includes('not found')) {
        alert('The content to print is not available.')
      }
    }
  })
}
</script>

Pop-up blocked

Browsers may block the print window:
<script setup>
import { usePrint } from 'vue-print-it'

const { print } = usePrint()

function handlePrint() {
  print('content', {
    onPrintError: (error) => {
      if (error.message.includes('blocked') || error.message.includes('popup')) {
        alert('Please allow pop-ups for this site to enable printing.')
      }
    }
  })
}
</script>

Timeout errors

If content takes too long to load:
<script setup>
import { usePrint } from 'vue-print-it'

const { print } = usePrint()

function handlePrint() {
  print('content', {
    timeout: 3000, // Increase timeout for slow content
    onPrintError: (error) => {
      if (error.message.includes('timeout')) {
        alert('Print preparation timed out. Please try again.')
      }
    }
  })
}
</script>

Bridge connection errors

When using the bridge plugin:
<script setup>
import { usePrint } from 'vue-print-it'

const { print, getBridgeStatus } = usePrint()

async function handlePrint() {
  // Check bridge availability first
  const status = await getBridgeStatus()
  
  if (!status) {
    alert('Print bridge is not available. Using browser print dialog instead.')
  }
  
  print('content', {
    useBridge: !!status,
    onPrintError: (error) => {
      if (error.message.includes('bridge')) {
        console.error('Bridge error, falling back to browser print')
        // Retry without bridge
        print('content', { useBridge: false })
      }
    }
  })
}
</script>

User-friendly error messages

Provide helpful error messages to users:
<template>
  <div>
    <div id="content">
      <h1>Document</h1>
      <p>Content to print</p>
    </div>
    
    <button @click="handlePrint" :disabled="isPrinting">
      {{ isPrinting ? 'Printing...' : 'Print' }}
    </button>
    
    <div v-if="error" class="error-message">
      <strong>Unable to print</strong>
      <p>{{ error.userMessage }}</p>
      <button @click="retryPrint">Try Again</button>
      <button @click="error = null">Dismiss</button>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { usePrint } from 'vue-print-it'

const { print } = usePrint()
const isPrinting = ref(false)
const error = ref(null)

function getUserFriendlyMessage(error: Error): string {
  if (error.message.includes('not found')) {
    return 'The content you are trying to print is not available.'
  }
  if (error.message.includes('blocked') || error.message.includes('popup')) {
    return 'Pop-ups are blocked. Please enable pop-ups for this site.'
  }
  if (error.message.includes('timeout')) {
    return 'The print preview is taking too long. Please try again.'
  }
  if (error.message.includes('bridge')) {
    return 'Unable to connect to the print service. Using browser print instead.'
  }
  return 'An unexpected error occurred. Please try again.'
}

async function handlePrint() {
  isPrinting.value = true
  error.value = null
  
  try {
    await print('content', {
      onPrintError: (err) => {
        error.value = {
          original: err,
          userMessage: getUserFriendlyMessage(err)
        }
      }
    })
  } catch (err) {
    error.value = {
      original: err,
      userMessage: getUserFriendlyMessage(err)
    }
  } finally {
    isPrinting.value = false
  }
}

function retryPrint() {
  error.value = null
  handlePrint()
}
</script>

<style scoped>
.error-message {
  margin-top: 20px;
  padding: 15px;
  background: #fee;
  border: 1px solid #fcc;
  border-radius: 4px;
}

.error-message button {
  margin-right: 10px;
  margin-top: 10px;
}
</style>

Logging and debugging

Log errors for debugging:
<script setup>
import { usePrint } from 'vue-print-it'

const { print } = usePrint()

function logPrintError(error: Error, context: Record<string, any>) {
  // Log to console
  console.error('Print error:', {
    message: error.message,
    stack: error.stack,
    ...context
  })
  
  // Send to error tracking service
  if (window.Sentry) {
    window.Sentry.captureException(error, {
      tags: {
        action: 'print',
        documentType: context.documentType
      },
      extra: context
    })
  }
  
  // Log to analytics
  if (window.analytics) {
    window.analytics.track('Print Error', {
      error: error.message,
      ...context
    })
  }
}

function handlePrint() {
  const context = {
    documentType: 'invoice',
    documentId: 'INV-12345',
    timestamp: new Date().toISOString(),
    userAgent: navigator.userAgent
  }
  
  print('invoice', {
    onPrintError: (error) => {
      logPrintError(error, context)
    }
  })
}
</script>

Fallback strategies

Provide alternative methods if printing fails:
<template>
  <div>
    <div id="content">
      <h1>Document</h1>
      <p>Content to print</p>
    </div>
    
    <div class="print-actions">
      <button @click="handlePrint">Print</button>
      <button @click="downloadPDF" v-if="showFallback">
        Download PDF Instead
      </button>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { usePrint } from 'vue-print-it'

const { print } = usePrint()
const showFallback = ref(false)
const errorCount = ref(0)

async function handlePrint() {
  try {
    await print('content', {
      onPrintError: (error) => {
        errorCount.value++
        
        // Show fallback option after 2 failures
        if (errorCount.value >= 2) {
          showFallback.value = true
          alert('Having trouble printing? Try downloading a PDF instead.')
        }
      }
    })
  } catch (error) {
    console.error('Print failed:', error)
  }
}

function downloadPDF() {
  // Implement PDF download logic
  window.location.href = '/api/documents/download-pdf'
}
</script>

Validation before printing

Validate content before attempting to print:
<script setup>
import { ref } from 'vue'
import { usePrint } from 'vue-print-it'

const { print } = usePrint()

function validateContent(elementId: string): { valid: boolean; error?: string } {
  // Check if element exists
  const element = document.getElementById(elementId)
  if (!element) {
    return { valid: false, error: 'Element not found' }
  }
  
  // Check if element has content
  if (!element.textContent?.trim()) {
    return { valid: false, error: 'Element is empty' }
  }
  
  // Check if element is visible
  if (element.offsetParent === null) {
    return { valid: false, error: 'Element is hidden' }
  }
  
  return { valid: true }
}

function handlePrint() {
  const validation = validateContent('content')
  
  if (!validation.valid) {
    alert(`Cannot print: ${validation.error}`)
    return
  }
  
  print('content', {
    onPrintError: (error) => {
      console.error('Print error:', error)
    }
  })
}
</script>

Retry logic

Implement automatic retry with exponential backoff:
<script setup>
import { usePrint } from 'vue-print-it'

const { print } = usePrint()

async function printWithRetry(
  elementId: string,
  maxRetries: number = 3,
  baseDelay: number = 1000
) {
  let lastError: Error | null = null
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      await print(elementId)
      return // Success
    } catch (error) {
      lastError = error as Error
      console.warn(`Print attempt ${attempt + 1} failed:`, error)
      
      if (attempt < maxRetries - 1) {
        // Wait before retrying (exponential backoff)
        const delay = baseDelay * Math.pow(2, attempt)
        await new Promise(resolve => setTimeout(resolve, delay))
      }
    }
  }
  
  // All retries failed
  throw new Error(`Print failed after ${maxRetries} attempts: ${lastError?.message}`)
}

async function handlePrint() {
  try {
    await printWithRetry('content')
    console.log('Print succeeded')
  } catch (error) {
    console.error('Print failed permanently:', error)
    alert('Unable to print after multiple attempts. Please try again later.')
  }
}
</script>

Debugging tips

Always check the browser console for error messages and stack traces.
Print behavior can vary between browsers. Test in Chrome, Firefox, Safari, and Edge.
Elements with display: none or visibility: hidden may not print correctly:
const element = document.getElementById('content')
console.log('Visible:', element.offsetParent !== null)
External stylesheets or images may fail to load due to CORS:
print('content', {
  preserveStyles: false, // Try without styles
  onPrintError: (error) => {
    if (error.message.includes('CORS')) {
      console.error('CORS issue detected')
    }
  }
})
Complex documents with many images may need more time:
print('content', {
  timeout: 5000 // Increase from default 1000ms
})

Error recovery

Provide options to recover from errors:
<template>
  <div>
    <div id="content">
      <h1>Document</h1>
      <p>Content to print</p>
    </div>
    
    <button @click="handlePrint">Print</button>
    
    <div v-if="lastError" class="error-recovery">
      <p class="error-message">{{ lastError.message }}</p>
      
      <div class="recovery-options">
        <button @click="retryWithoutStyles">
          Retry without styles
        </button>
        <button @click="retrySimplified">
          Retry simplified version
        </button>
        <button @click="openNewTab">
          Open in new tab
        </button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { usePrint } from 'vue-print-it'

const { print } = usePrint()
const lastError = ref<Error | null>(null)

async function handlePrint() {
  lastError.value = null
  
  try {
    await print('content', {
      preserveStyles: true,
      onPrintError: (error) => {
        lastError.value = error
      }
    })
  } catch (error) {
    lastError.value = error as Error
  }
}

function retryWithoutStyles() {
  lastError.value = null
  print('content', { preserveStyles: false })
}

function retrySimplified() {
  lastError.value = null
  // Create simplified version
  const content = document.getElementById('content')
  if (content) {
    const simplified = document.createElement('div')
    simplified.id = 'simplified-content'
    simplified.textContent = content.textContent
    document.body.appendChild(simplified)
    
    print('simplified-content', {
      onAfterPrint: () => {
        simplified.remove()
      }
    })
  }
}

function openNewTab() {
  const content = document.getElementById('content')
  if (content) {
    const printWindow = window.open('', '_blank')
    if (printWindow) {
      printWindow.document.write(content.innerHTML)
      printWindow.document.close()
      printWindow.print()
    }
  }
}
</script>

Next steps

Event callbacks

Learn about print lifecycle events

Configuration

View all configuration options

Bridge printing

Alternative printing with bridge

API Reference

Complete API documentation

Build docs developers (and LLMs) love