Skip to main content

Vue.js integration: troubleshooting

This page covers error handling patterns and common issues when integrating the Weavr SDK with Vue.js. For setup instructions, see Getting started.

Error handling

SDK initialization errors

<script setup lang="ts">
import { ref, onMounted } from "vue";

const sdkError = ref<string | null>(null);
const isReady = ref(false);

onMounted(() => {
// Check if SDK loaded
if (!window.OpcUxSecureClient) {
sdkError.value =
"Weavr SDK failed to load. Check your internet connection and ensure the script tag is in index.html.";
return;
}

try {
window.OpcUxSecureClient.init("your_ui_key");
isReady.value = true;
} catch (e) {
sdkError.value = `SDK initialization failed: ${e instanceof Error ? e.message : "Unknown error"}`;
}
});
</script>

<template>
<div v-if="sdkError" class="error-banner">{{ sdkError }}</div>
<slot v-else-if="isReady"></slot>
<div v-else>Initializing...</div>
</template>

Component mount errors

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";

const containerRef = ref<HTMLElement | null>(null);
const mountError = ref<string | null>(null);

let input: any = null;

onMounted(() => {
try {
const form = window.OpcUxSecureClient.form();
input = form.input("password", "password", { placeholder: "Password" });

if (!containerRef.value) {
throw new Error("Container element not found");
}

input.mount(containerRef.value);
} catch (e) {
mountError.value =
e instanceof Error ? e.message : "Failed to mount component";
console.error("Mount error:", e);
}
});

onUnmounted(() => {
try {
input?.unmount();
} catch (e) {
// Unmount errors are typically safe to ignore
console.warn("Unmount warning:", e);
}
});
</script>

<template>
<div v-if="mountError" class="error">{{ mountError }}</div>
<div v-else ref="containerRef"></div>
</template>

Tokenization errors

<script setup lang="ts">
const handleSubmit = () => {
form.tokenize(
(tokens: Record<string, string>) => {
if (!tokens.password) {
// Empty token usually means validation failed
error.value = "Please enter a valid password";
return;
}
// Process tokens...
},
(e: Error) => {
// Tokenization error callback (if supported)
error.value = `Tokenization failed: ${e.message}`;
}
);
};
</script>

Vue error boundary

Create an error boundary component for Weavr integrations:

<!-- WeavrErrorBoundary.vue -->
<script setup lang="ts">
import { ref, onErrorCaptured } from "vue";

const error = ref<Error | null>(null);

onErrorCaptured((err) => {
error.value = err;
console.error("Weavr component error:", err);
return false; // Prevent error from propagating
});

const retry = () => {
error.value = null;
};
</script>

<template>
<div v-if="error" class="error-boundary">
<p>Something went wrong with the secure component.</p>
<button @click="retry">Try Again</button>
</div>
<slot v-else></slot>
</template>

Usage:

<template>
<WeavrErrorBoundary>
<PasswordInput />
</WeavrErrorBoundary>
</template>

Common pitfalls and troubleshooting

Error: "TypeError: P.has is not a function"

Symptoms: error appears in console immediately when component mounts.

Cause: the Weavr SDK was imported through a JavaScript bundler (Vite, Webpack) instead of being loaded via a script tag.

Solution:

  1. Remove any import statements for the Weavr SDK
  2. Add the SDK script tag to your index.html:
<script src="https://sandbox.weavr.io/app/secure/static/client.1.js"></script>
  1. Access the SDK via window.OpcUxSecureClient

Component not rendering

Symptoms: the container div exists but remains empty.

Possible causes and solutions:

  1. SDK not loaded: check window.OpcUxSecureClient exists before using it
  2. Mounting before DOM ready: ensure mount() is called in onMounted()
  3. Wrong container reference: verify ref is correctly assigned
<script setup>
onMounted(() => {
console.log("Container:", containerRef.value); // Debug: should not be null
console.log("SDK:", window.OpcUxSecureClient); // Debug: should exist
});
</script>

Component disappears after route change

Symptoms: component works initially but disappears when navigating away and back.

Cause: the SDK component wasn't properly unmounted, causing state issues.

Solution: always call unmount() in onUnmounted():

<script setup>
let input: any = null

onMounted(() => {
input = form.input('password', 'password', {})
input.mount(containerRef.value)
})

onUnmounted(() => {
// Critical: Clean up to prevent state issues
try {
if (input && typeof input.unmount === 'function') {
input.unmount();
}
} catch (e) {
console.error("Error unmounting component:", e);
}
})
</script>

For route-based components, consider using a :key to force remounting:

<template>
<router-view :key="$route.fullPath" />
</template>

Token is undefined after submit

Symptoms: tokens.password is undefined in the tokenize callback.

Possible causes:

  1. User left input empty: add validation before tokenizing
  2. Input validation failed: the SDK validates input format internally
  3. Async timing issue: token is only available inside the callback

Solution:

<script setup>
const handleSubmit = () => {
form.tokenize((tokens) => {
// Check inside callback
if (!tokens.password) {
error.value = "Please enter a valid password";
return;
}

// Safe to use token here
submitToServer(tokens.password);
});

// WRONG: tokens not available here
// submitToServer(tokens.password)
};
</script>

Memory leaks

Symptoms: memory usage increases over time, especially with repeated navigation.

Cause: the SDK components are not being unmounted when Vue components are destroyed.

Solution: always clean up in onUnmounted():

<script setup>
// Track all SDK instances
let form: any = null
let inputs: any[] = []

onMounted(() => {
form = window.OpcUxSecureClient.form()

const password = form.input('password', 'password', {})
password.mount(passwordRef.value)
inputs.push(password)

const confirmPassword = form.input('confirmPassword', 'confirmPassword', {})
confirmPassword.mount(confirmPasswordRef.value)
inputs.push(confirmPassword)
})

onUnmounted(() => {
// Clean up all inputs
try {
inputs.forEach(input => {
if (input && typeof input.unmount === 'function') {
input.unmount();
}
});
inputs = [];
} catch (e) {
console.error("Error unmounting components:", e);
}
})
</script>

SDK iframe initialization warning

Symptoms: console warning: "Attempting to use 'onMessage' for <inline-menu-ready> without registering a handler"

Cause: the SDK's iframe communication handlers are not fully registered before the component mounts.

Solution: add a small delay before mounting to allow SDK initialization:

<script setup>
let input: any = null

onMounted(() => {
if (!window.OpcUxSecureClient) {
console.error("SDK not loaded");
return;
}

try {
const form = window.OpcUxSecureClient.form();
input = form.input("password", "password", {
placeholder: "Enter password"
});

// Add delay to let SDK fully initialize iframe handlers
setTimeout(() => {
if (containerRef.value) {
input.mount(containerRef.value);
}
}, 100);
} catch (e) {
console.error("Error initializing component:", e);
}
});
</script>

Note: this warning is cosmetic and doesn't prevent the component from functioning correctly, but adding the delay eliminates it.

Associate callback not firing

Symptoms: code after associate() never executes.

Possible causes:

  1. Invalid auth token: verify the token is valid and not expired
  2. Network issues: check browser network tab for failed requests
  3. Wrong environment: sandbox token used with Live SDK URL (or vice versa)

Solution: always provide an error callback:

<script setup>
onMounted(() => {
window.OpcUxSecureClient.associate(
`Bearer ${authToken}`,
() => {
console.log("Associate succeeded");
// Continue setup...
},
(error) => {
console.error("Associate failed:", error);
// Handle error - show message to user
showError.value = "Authentication failed. Please try again.";
}
);
});
</script>