Welcome to Oshon · v1.0  ·  Now in public beta for enterprise teams Read the launch notes

Troubleshooting

Specific error messages and their fixes, organized by what you'll see on screen. Use Ctrl + F to search for the exact text of your error.

If you don't find your problem here, check the Get Started walkthrough, then email support@oshon.ai with:

  1. The full error message (copy-paste, not a screenshot if you can avoid it)
  2. Output of node --version
  3. Output of cat package.json — we just need the dependencies block

Install errors

"Cannot find module @oshon-ai/components" or its types

You ran pnpm dev and the build fails:

Module not found: Can't resolve '@oshon-ai/components'

Fix: the package wasn't installed. Run:

pnpm add @oshon-ai/components @oshon-ai/tokens @oshon-ai/primitives

You need all three packages — components depends on tokens + primitives. Installing just one will throw the same error for the missing peer.

"Peer dependency warning: react@^18.0.0"

The install succeeds but prints warnings like:

WARN  unmet peer react@">=18.0.0 <20.0.0": found 17.x.x

Fix: upgrade React to 18 or 19. Oshon doesn't support React 17 — the components rely on hooks and concurrent features that landed in 18.

pnpm add react@^18 react-dom@^18
# or for React 19:
pnpm add react@^19 react-dom@^19

Components behave oddly after upgrading only one of the three packages

The three core packages — @oshon-ai/components, @oshon-ai/tokens, @oshon-ai/primitives — are released in lockstep (same version number, every release). If your package.json ends up with mismatched versions (typically because you ran pnpm up @oshon-ai/components alone), you may see:

  • Peer-dependency warnings during install: WARN unmet peer @oshon-ai/tokens@0.10.0: found 0.9.0
  • Components rendering with stale tokens (wrong colors, wrong sizes).
  • TypeScript errors about props that exist in your code but not in the installed type definitions.

Fix: always upgrade all three together:

pnpm add @oshon-ai/components@latest \
         @oshon-ai/tokens@latest \
         @oshon-ai/primitives@latest

Verify the versions match:

pnpm list @oshon-ai/components @oshon-ai/tokens @oshon-ai/primitives
# all three should show the same version

Visual issues

Components render without color / look like grey rectangles

The button shows up but it's grey, the corners aren't rounded, the text is in your default font.

Cause: the design tokens aren't wired into your Tailwind v4 stylesheet, so utility classes like bg-primary-500 resolve to nothing.

Fix: open app/globals.css (or whatever file you load Tailwind from) and put these three lines at the top:

app/globals.css
@import 'tailwindcss';
@import '@oshon-ai/tokens/css';
@import '@oshon-ai/tokens/tailwind';

They must be CSS @import statements (in a .css file), not JS imports — Tailwind needs to see them at compile time to wire the @theme bridge. Reload — the button should now be teal (default Oshon primary). If it's still grey:

  1. Inspect the button in DevTools → Computed → look for --oshon-color-primary-500 on :root. If missing, the @oshon-ai/tokens/css import didn't run.
  2. Check the rendered class — if you see className="bg-primary-500" but the computed background-color is empty, Tailwind isn't compiling. Verify pnpm list tailwindcss shows 4.x.
  3. If you load Tailwind a different way (separate tailwind.css entry, not globals.css), put the three @imports in that file instead — they all need to reach Tailwind's compiler.

Page flashes light mode for a moment, then turns dark

Common when toggling dark mode — for ~100ms the page renders in light mode before the dark theme kicks in.

Cause: you set data-oshon-theme="dark" inside a React effect, which runs after the initial paint.

Fix: set the attribute on the <html> element via an inline script that runs before React hydrates. In Next.js:

app/theme-bootstrap.tsx
// Server component — runs in <head> before hydration
export function ThemeBootstrap() {
  return (
    <script
      dangerouslySetInnerHTML={{
        __html: `
          try {
            var t = localStorage.getItem('oshon-theme') || 'light';
            document.documentElement.setAttribute('data-oshon-theme', t);
          } catch (e) {}
        `,
      }}
    />
  );
}

Render <ThemeBootstrap /> inside <head> in your root layout.

Text is unreadable in dark mode (dark text on dark background)

The html element doesn't have data-oshon-theme="dark" set on it, so the dark-mode media query auto-fires (because of OS preferences) but the explicit override that the components key off is missing.

Fix: always set the attribute on the html element, even in light mode:

// Pin light mode explicitly:
document.documentElement.setAttribute('data-oshon-theme', 'light');

// Or dark:
document.documentElement.setAttribute('data-oshon-theme', 'dark');

The Oshon tokens use @media (prefers-color-scheme: dark) :root:not([data-oshon-theme='light']) — so an unset attribute opts INTO dark mode when the OS prefers dark. Setting 'light' explicitly opts out.

Text shows a serif font instead of Lato

Oshon expects Lato 400 + 700 to be loaded by your app. If they aren't, browsers fall back to whatever the system serif is.

Fix: add Google Fonts in your root layout:

app/layout.tsx
import { Lato } from 'next/font/google';

const lato = Lato({
  subsets: ['latin'],
  weight: ['400', '700'],
  variable: '--oshon-font-family',
});

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={lato.variable}>
      <body>{children}</body>
    </html>
  );
}

Heads up: Lato only ships weights 400 and 700. Setting fontWeight: 500 or 600 on text rendered in Lato silently snaps to the wrong weight (500→400, 600→700). Use one of the two real weights or switch fonts.

TypeScript errors

"Cannot find module '@oshon-ai/components' or its corresponding type declarations"

You see this in your editor or when running tsc:

Cannot find module '@oshon-ai/components' or its corresponding type declarations.
  There are types at '.../node_modules/@oshon-ai/components/dist/index.d.ts',
  but this result could not be resolved under your current 'moduleResolution' setting.

Cause: your tsconfig.json uses an old moduleResolution setting that doesn't follow the package exports map.

Fix: in tsconfig.json, set:

tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "bundler",
    // ...your other options
  }
}

If you can't switch to bundler (older toolchain), use "node16" or "nodenext" instead — both honor the package exports field.

"Cannot use JSX unless the --jsx flag is provided"

Compile error in a .tsx file when you import an Oshon component.

Cause: your tsconfig.json doesn't enable JSX.

Fix:

tsconfig.json
{
  "compilerOptions": {
    "jsx": "react-jsx"
  }
}

Next.js / Server-side rendering

"Event handlers cannot be passed to Client Component props"

Most Oshon components are Client Components — they use useState, useEffect, refs, etc. If you import them into a Server Component file (the default in Next.js App Router), you'll see one of these:

Error: Event handlers cannot be passed to Client Component props.
  <... onClick={function onClick} ...>
                ^^^^^^^^^^^^^^^^^^
  If you need interactivity, consider converting part of this to a
  Client Component.

or:

Error: Functions cannot be passed directly to Client Components unless
  you explicitly expose it by marking it with "use server".

Fix: add 'use client' as the very first line of the file that renders the Oshon component:

app/page.tsx
'use client';

import { ButtonHug } from '@oshon-ai/components';

export default function HomePage() {
  return <ButtonHug onClick={() => alert('hi')}>Click me</ButtonHug>;
}

A small set of Oshon components are RSC-safe (no client boundary): Badge, BadgeDot, Tag, CounterChip, Skeleton. These render fine inside a Server Component without the directive (verified against the package source — none of them ship a 'use client' pragma).

"Hydration failed because the server rendered HTML didn't match the client"

Usually triggered by dark mode — the server doesn't know the user's OS theme preference, so it renders light, then the client flips to dark and React detects the mismatch.

Fix: add suppressHydrationWarning to the html element:

app/layout.tsx
<html lang="en" suppressHydrationWarning>
  ...
</html>

This is the standard React + theme-aware-app workaround — it tells React to ignore mismatches on this one element, where the mismatch is intentional (we WANT the client to override the server theme).

Tailwind CSS issues

Oshon components render as unstyled grey boxes

Colors and tokens resolve, but the components themselves have no layout, spacing, or shape — they look like raw HTML.

Cause: Oshon ships its utility class names inside the component JS (that's what makes them tree-shakeable). Tailwind v4 does not scan node_modules by default, so it never sees those class names and never generates their CSS rules. Importing @oshon-ai/tokens/tailwind wires up the token variables but not the component utilities — which is why colors look right but layout is missing.

Fix: add an @source line per Oshon package you install, pointing at it in node_modules:

app/globals.css
@import 'tailwindcss';
@import '@oshon-ai/tokens/css';
@import '@oshon-ai/tokens/tailwind';

/* REQUIRED: let Tailwind scan Oshon's class names in node_modules.
   Path is relative to THIS file (App Router → ../node_modules). */
@source '../node_modules/@oshon-ai/components';
@source '../node_modules/@oshon-ai/data';   /* only if you use the data grid */

Restart the dev server after adding it (Tailwind caches its source scan). If you use a monorepo or a hoisted node_modules, adjust the relative depth accordingly.

Component classes work but my own Tailwind classes don't

You can render Oshon components fine, but Tailwind utilities you write yourself (className="text-red-500") have no effect.

Cause: Tailwind v4 isn't scanning your source files. By default v4 auto-detects, but if your project layout is unusual (e.g. an src/ root), you may need to point it explicitly with @source directives in your CSS:

app/globals.css
@import 'tailwindcss';
@import '@oshon-ai/tokens/css';
@import '@oshon-ai/tokens/tailwind';

/* Tell Tailwind v4 where to find class names if auto-detect misses */
@source "../app/**/*.{ts,tsx}";
@source "../components/**/*.{ts,tsx}";

Path syntax is relative to the CSS file. Tailwind v4 dropped the content array — everything lives in the CSS file now.

"I have Tailwind v3 — does Oshon work on it?"

Short answer: no. Oshon requires Tailwind v4.

Components ship Tailwind utility class names baked into the JavaScript (e.g. className="bg-primary-500 rounded-md ..."). Those class names only resolve to real CSS when Tailwind v4's @theme directive maps them to Oshon's CSS variables — and v3 doesn't support @theme. On v3 the components render unstyled.

Check which version you're on:

pnpm list tailwindcss
# look for: tailwindcss 4.x.x

Upgrade from v3 to v4 (most fresh Next.js 15.1+ projects already have v4) — three steps:

Step 1. Install v4 + the new postcss plugin:

pnpm add -D tailwindcss@latest @tailwindcss/postcss@latest

Step 2. Update your postcss.config.mjs (or .js) — v4 ships its own postcss plugin and the v3 plugin is removed:

postcss.config.mjs (before — v3)
export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};
postcss.config.mjs (after — v4)
export default {
  plugins: {
    '@tailwindcss/postcss': {},
  },
};

Step 3. Convert your globals.css from v3 directives to v4 imports:

globals.css (before — v3)
@tailwind base;
@tailwind components;
@tailwind utilities;
globals.css (after — v4)
@import 'tailwindcss';
@import '@oshon-ai/tokens/css';
@import '@oshon-ai/tokens/tailwind';

You can usually delete tailwind.config.ts after this — v4 reads custom theme values from CSS via @theme directives. If you had complex plugins or custom utilities, keep the file; v4 still reads it.

The full v3→v4 migration guide on tailwindcss.com covers any custom rules you had in tailwind.config.ts.

Tailwind v4 is installed but Oshon utilities still don't resolve

You're on Tailwind v4, you've imported @oshon-ai/tokens/tailwind, but className="bg-primary-500" still produces no background color.

Most common cause: the @import statements are in the wrong order. Tailwind needs the engine imported first:

globals.css
/* ✅ correct order */
@import 'tailwindcss';
@import '@oshon-ai/tokens/css';
@import '@oshon-ai/tokens/tailwind';

/* ❌ wrong — @theme will be ignored */
@import '@oshon-ai/tokens/tailwind';
@import 'tailwindcss';

Other causes:

  • Your project has both a globals.css and a separate tailwind.css entry. Make sure the three @imports are in the file Tailwind compiles, not elsewhere.
  • Your bundler tree-shook the node_modules/@oshon-ai/tokens CSS files. Check the bundler's "exclude" patterns.

Still stuck?

Email support@oshon.ai with the diagnostic info from the top of this page (full error, Node version, package.json deps). Paying customers get a response within 1 business day.