---
title: "Troubleshooting - BYO"
slug: "troubleshooting-byo"
updated: 2026-10-07T18:51:36Z
published: 2026-10-07T18:51:36Z
canonical: "docs.unqork.io/troubleshooting-byo"
---
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.unqork.io/llms.txt
> Use this file to discover all available pages before exploring further.
# Troubleshooting - BYO
Common issues and solutions for BYO custom component development.
## Component Not Rendering
### Component Missing from the Module Builder
**Symptoms**:
- Custom Component displays an empty selector.
- The component is not listed in the available components.
**Solution**:
**1. Bundle Not Uploaded**
```bash
# Check if .tar.gz was uploaded
# Go to Admin → Custom Assets
# Verify your component displays in the list
```
**2. Build Failed**
```bash
# Rebuild
npm run build
# Check for errors in console
# Fix any TypeScript or build errors
```
**3. Wrong Runtime Version**
Check `package.json` `byo.runtimeVersion` matches your environment. This field is optional and present if added manually — if it is not in your `package.json`, skip this step:
```json
{
"byo": {
"runtimeVersion": "1.0.0"
}
}
```
### Component Renders as Empty
**Symptoms**:
- A component space displays on the canvas.
- No content visible.
- No errors in the console.
**Solution**:
**1. Missing Render Logic**
```typescript
// ❌ Bad - no render implementation
export class MyComponent extends HTMLElement {
connectedCallback() {
// Nothing here
}
}
// ✅ Good - implements render
export class MyComponent extends HTMLElement {
connectedCallback() {
this.render()
}
render() {
this.innerHTML = `
Hello
`
}
}
```
**2. Shadow DOM Without Content**
```typescript
// ❌ Bad - shadow DOM but no content
connectedCallback() {
this.attachShadow({ mode: 'open' })
}
// ✅ Good - shadow DOM with content
connectedCallback() {
this.attachShadow({ mode: 'open' })
this.shadowRoot.innerHTML = `Hello
`
}
```
**3. Properties Not Set**
Check that properties are being set:
```typescript
set label(value: string) {
console.log('Label set:', value) // Debug log
this._label = value
this.render()
}
```
### Component Shows Error Message
**Symptoms**:
- Error boundary displays "Component failed to load".
- Browser console displays errors.
**Solution**: Use the following steps to identify the source of the error.
**1. Check browser console**
Press F12 and look for:
- JavaScript errors.
- Failed network requests.
- Type errors.
**2. Check Network tab**
Verify the bundle loaded correctly:
1. Open the Network tab.
2. Refresh the page.
3. Filter by JS.
4. Check if your bundle displays with status 200.
**3. Inspect Elements tab**
Check if the custom element is defined:
```javascript
// In browser console
console.log(customElements.get('my-component'))
// Should return constructor, not undefined
```
**4. Test in dev harness**
```bash
npm run dev
```
If it works in dev harness but not in Unqork:
1. Check for platform API incompatibilities.
2. Verify callbacks are optional chained (`?.`).
3. Check for DOM access outside your component.
## Properties and State Issues
### Properties Not Updating Component
**Symptoms**:
- Changing settings in Module Builder has no effect.
- Component displays stale data.
**Solution**:
**1. Missing Setters**
```typescript
// ❌ Bad - no setter
class MyComponent extends HTMLElement {
label: string = ''
}
// ✅ Good - implements setter
class MyComponent extends HTMLElement {
private _label: string = ''
set label(value: string) {
this._label = value
this.render()
}
}
```
**2. Setter Doesn't Trigger Render**
```typescript
set label(value: string) {
this._label = value
// ❌ Missing: this.render()
}
// ✅ Good
set label(value: string) {
this._label = value
this.render() // Trigger re-render
}
```
**3. Type Mismatch**
```typescript
set count(value: unknown) {
// Validate type
if (typeof value !== 'number') {
console.warn('count must be number, got:', typeof value, value)
return
}
this._count = value
this.render()
}
```
**Debug property values**:
```typescript
set myProp(value: unknown) {
console.log('myProp set:', value, 'type:', typeof value)
this._myProp = value
this.render()
}
```
### Submission Data Not Updating
**Symptoms**:
- Calling `onSubmissionUpdate` has no effect.
- Other components don't see updated data.
**Solution**:
**1. Callback Not Wired**
Check the Module Builder triggers configuration:
```json
{
"triggers": {
"onSubmissionUpdate": {
// Should be configured
}
}
}
```
`onSubmissionUpdate` doesn't need configuration. It's handled automatically.
**2. Calling Incorrectly**
```typescript
// ❌ Bad - calling without optional chaining
this.onSubmissionUpdate(newValue) // Throws if undefined
// ✅ Good - safe optional chaining
this.onSubmissionUpdate?.(newValue)
```
**3. Passing Undefined**
```typescript
// Check value before updating
if (value !== undefined) {
this.onSubmissionUpdate?.(value)
}
```
**Debug submission updates**:
```typescript
handleChange(value: string) {
console.log('Updating submission:', value)
console.log('Callback exists?', !!this.onSubmissionUpdate)
this.onSubmissionUpdate?.(value)
}
```
## Event and Callback Issues
### Callbacks Not Firing
**Symptoms**:
- Events don't trigger workflows.
- Trigger configuration has no effect.
**Solution**:
**1. Missing Optional Chaining**
```typescript
// ❌ Bad - throws if callback undefined
this.onButtonClicked({ label: this._label })
// ✅ Good - safe optional chaining
this.onButtonClicked?.({ label: this._label })
```
**2. Wrong Callback Name**
Check that manifest.json and the Module Builder configuration match:
```json
// manifest.json
{
"events": [
{
"type": "buttonClicked" // Must match property name
}
]
}
```
```typescript
// Component
this.onButtonClicked?.({ ... }) // Must be on[EventType]
```
**3. Trigger Not Configured**
In Module Builder, verify trigger exists:
```json
{
"triggers": {
"onButtonClicked": {
"contextId": "clickData",
"targetId": "someLogicComponent"
}
}
}
```
**4. Timing Issue**
Callbacks are set after `connectedCallback`. If you call them immediately, they might not exist yet:
```typescript
// ❌ Bad - callback might not be set yet
connectedCallback() {
this.onReady?.() // May be undefined
}
// ✅ Good - wait for platform to wire callbacks
connectedCallback() {
setTimeout(() => {
this.onReady?.()
}, 0)
}
```
**Debug callbacks**:
```typescript
handleClick() {
console.log('Callbacks available:', {: typeof this.onButtonClicked,: typeof this.onSubmissionUpdate,
})
this.onButtonClicked?.({ label: this._label })
}
```
## Build and Bundle Issues
### Build Fails
Build failures usually trace to of three issues.
**1. TypeScript Errors**
```plaintext
error TS2304: Cannot find name 'X'
```
**Solution**:
```bash
# Install missing types
npm install -D @types/X
# Or fix TypeScript errors in code
```
**2. Module Not Found**
```plaintext
Cannot find module './MyComponent'
```
**Solution**:
1. Check that the file exists at the specified .
2. Check that the import path is correct.
3. Check the file extension (`.ts` vs `.tsx`).
**3. Syntax Errors**
```plaintext
Unexpected token ')'
```
**Solution**:
1. Fix the JavaScript/TypeScript syntax.
2. Check for missing closing braces, brackets, and parentheses.
**Run build with verbose logging**:
```bash
npm run build -- --mode development
```
### Bundle Too Large
**Symptoms**:
- Bundle size > 500KB.
- Slow page loads.
- Performance warnings.
**Solution**:
**1. Check bundle size**
```bash
npm run build
ls -lh dist/*.js
```
**2. Use code splitting**
```typescript
// ❌ Bad - imports everything upfront
import * as d3 from 'd3'
// ✅ Good - lazy load
async loadD3() {
const d3 = await import('d3')
return d3
}
```
**3. Import what you need**
```typescript
// ❌ Bad - imports entire library
import _ from 'lodash'
// ✅ Good - imports specific functions
import debounce from 'lodash/debounce'
import throttle from 'lodash/throttle'
```
**4. Remove unused dependencies**
```bash
npm uninstall unused-library
```
**5. Analyze bundle**
```bash
# Add to package.json
"scripts": {
"analyze": "vite build --mode analyze"
}
```
### Validation Fails
Validation errors occur when the component manifest doesn't match the required schema.
**1. Manifest Schema Invalid**
```plaintext
manifest.json validation failed
```
**Solution**: Check required fields in `manifest.json`:
```json
{
"name": "my-component", // Required
"main": "my-component.js", // Required
"type": "custom", // Required
"productType": "BYO", // Required
"version": "1.0.0", // Required
"runtimeVersion": "1.0.0", // Required
"description": "...", // Required
"components": [] // Optional
}
```
**2. Export Missing**
```plaintext
Component 'myButton' export not found in bundle
```
**Solution**: Ensure the `entry.ts` exports match the manifest:
```typescript
// src/entry.ts
export const myButton = { // Name must match manifest
view: async () => MyButton,
model: async () => MyButtonModel,
}
```
**3. Missing View or Model**
```plaintext
Component 'myButton' export is missing 'view' function
```
**Solution**: The export must have both `view` and `model`:
```typescript
export const myButton = {
view: async () => MyButton, // Required
model: async () => MyButtonModel, // Required
}
```
## Dev Harness Issues
### Dev Harness Shows Blank Page
A blank page in the dev harness typically has of three causes.
**1. Port Already in Use**
```bash
# Error: Port 5173 already in use
# Use different port
npm run dev -- --port 5001
```
**2. Build Errors**
Check terminal for error messages:
```bash
# Look for compilation errors
# Fix TypeScript/JavaScript errors
```
**3. Missing Mock Scenarios**
Create at least mock scenario:
```typescript
// src/MyComponent.mocks.ts
import { defineMockScenario } from '@unqork/byo-sdk/testing'
export const defaultScenario = defineMockScenario({
name: 'Default',
props: {
label: 'Click me',
},
callbacks: ['onButtonClicked'],
})
```
### Mock Scenarios Not Appearing
If your scenarios don't appear in the selector, of the following issues is usually responsible.
**1. File Naming**
Scenarios must be in files matching `*.mocks.ts`:
```plaintext
✓ MyComponent.mocks.ts
✓ scenarios.mocks.ts
✗ MyComponent.scenarios.ts // Wrong
✗ mocks.ts // Wrong
```
**2. Export Format**
Export scenario objects:
```typescript
// ✅ Good
export const myScenario = defineMockScenario({
name: 'My Scenario',
props: { ... },
})
// ❌ Bad - not exported
const myScenario = defineMockScenario({ ... })
```
**3. Missing Name**
Scenarios need a name to appear in the selector:
```typescript
defineMockScenario({
name: 'Default', // Required
props: { ... },
})
```
## Performance Issues
### Slow Page Loads
Slow load times with BYO components usually trace to of four causes.
**1. Too Many BYO Components**
Each component adds overhead. Combine related components:
```plaintext
❌ 10 small components = 10 bundles to load
✅ 1 combined component = 1 bundle
```
**2. Large Bundle Size**
See [Bundle Too Large](/unqorkai/docs/troubleshooting-byo#bundle-too-large) for steps to reduce the bundle size.
**3. Synchronous Heavy Operations**
Use async with batching:
```typescript
async processItems(items: Item[]) {
const batchSize = 100
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize)
await processBatch(batch)
// Yield to browser
await new Promise(resolve => setTimeout(resolve, 0))
}
}
```
**4. Memory Leaks**
Clean up in `disconnectedCallback`:
```typescript
private interval: number | null = null
connectedCallback() {
this.interval = setInterval(this.update, 1000)
}
disconnectedCallback() {
if (this.interval) {
clearInterval(this.interval)
}
}
```
## Browser Compatibility Issues
### Component Works in Chrome but Not Safari
Browser compatibility issues typically come from modern API usage, Shadow DOM differences, or unsupported CSS features.
**1. Missing Polyfills**
Check if you're using any modern APIs:
- `structuredClone`: Use a polyfill or deep clone manually.
- `replaceAll`: Use `split().join()` instead.
- Optional chaining `?.`: Supported in all modern browsers.
**2. Shadow DOM Differences**
Test Shadow DOM behavior across browsers.
**3. CSS Features**
Some CSS features have browser-specific support:
- Container queries.
- `:has()` selector.
- Cascade layers.
**4. Test in All Target Browsers**
Test in Chrome, Firefox, Safari, and Edge.
## Getting Help
### Debug Checklist
Before asking for help:
- [ ] Check browser console for errors.
- [ ] Test in dev harness (`npm run dev`).
- [ ] Check bundle loaded in Network tab.
- [ ] Verify the custom element is defined in the console.
- [ ] Test with simple mock data.
- [ ] Check for TypeScript errors.
- [ ] Review [FAQ](/unqorkai/docs/faq-byo).
### Reporting Issues
When reporting bugs, include:
**1. SDK Version**:
```bash
npx byo version
```
**2. Error Messages**:
- Browser console errors.
- Build/validation errors.
- Stack traces.
**3. Minimal Reproduction**:
- Simplest code that demonstrates the problem.
- Steps to reproduce.
- Expected vs actual behavior.
**4. Environment**:
- Browser and version.
- Operating system.
- Node version.
Contact your Unqork account team or submit a support request through your organization's support portal.
---
**Changelog**
| Date | Change |
| --- | --- |
| 2026-10-01 | Converted em dash to period; added blank lines before all lists for correct MDX rendering (EN-8151). |
| 2026-05-01 | Initial publication |
JavaScript is an object-oriented computer programming language. It is most-commonly used for interactive effects in the browser.
APIs (application programming interfaces) are a set of protocols and definitions developers use to build and integrate application software. APIs act as the connective tissue between products and services.
The Document Object Model (DOM) is the data representation of objects that form the structure and content of a document on the web. The DOM represents the page.
Schema is a declarative language that defines the structure, content, and constraints of the data.
An object is a type of data structure that represents a single, self-contained entity that acts as a container for the characteristics of that entity.
Cascading Style Sheets (CSS) is a style sheet language used for presenting how a HTML or XML document looks to end-users.
APIs (application programming interfaces) are a set of protocols and definitions developers use to build and integrate application software. APIs act as the connective tissue between products and services.
A query lets you retrieve, access, manipulate, and delete data in a database.
Rendering is the process of loading components and displaying the final result on the front-end screen.