CherryHQ/cherry-studio · error · Error
[theme-contract] unsupported @import syntax: ${importValue}
Error message
[theme-contract] unsupported @import syntax: ${importValue} What it means
Thrown by the theme contract validator when an @import statement in a CSS file uses a syntax that is neither a quoted string (e.g., @import 'file.css'; or @import "file.css";) nor a url() function (e.g., @import url('file.css');). The extractImports function matches @import followed by a quoted string or url(...) and throws for any other format. This enforces a consistent import style and catches malformed @import statements.
Source
Thrown at packages/ui/scripts/validate-theme-contract.ts:102
return [...value.matchAll(/var\(\s*(--[^\s,)]+)/g)].map((match) => {
const name = match[1]
if (!CUSTOM_PROPERTY_NAME_PATTERN.test(name)) {
throw new Error(`[theme-contract] ${sourceName} references invalid custom property ${name}`)
}
return name
})
}
function extractImports(source: string): string[] {
return [...stripComments(source).matchAll(/@import\s+([^;]+);/g)].map((match) => {
const importValue = match[1].trim()
const stringMatch = importValue.match(/^(['"])([^'"]+)\1$/)
if (stringMatch) return stringMatch[2]
const urlMatch = importValue.match(/^url\(\s*(?:(['"])([^'"]+)\1|([^'")\s][^)]*?))\s*\)$/)
if (urlMatch) return (urlMatch[2] ?? urlMatch[3]).trim()
throw new Error(`[theme-contract] unsupported @import syntax: ${importValue}`)
})
}
function assertUnique(label: string, values: readonly string[]): void {
if (new Set(values).size !== values.length) {
throw new Error(`[theme-contract] ${label} contains duplicate names`)
}
}
function assertSurfacePairs(
label: string,
pairs: ReadonlyArray<readonly [surface: string, foreground: string]>,
variableNames: Set<string>
): void {
const surfaces = new Set<string>()
for (const [surface, foreground] of pairs) {
if (surface === foreground || surfaces.has(surface)) {View on GitHub (pinned to 726446b54c)
Solutions
- Rewrite the @import to use a quoted string: @import 'path/to/file.css';.
- If using url() syntax, ensure it's properly formatted: @import url('path/to/file.css');.
- If the @import has qualifiers (layer, supports), move them outside the string so the path itself is quoted: @import 'file.css' layer(theme);.
- Run the validator to confirm: npx tsx packages/ui/scripts/validate-theme-contract.ts.
Example fix
/* before — unquoted import */ @import tokens/colors.css; /* after — quoted string */ @import 'tokens/colors.css';
Defensive patterns
Strategy: validation
Validate before calling
// Validate @import syntax in CSS before committing
import { readFileSync } from 'node:fs'
function checkImports(cssPath: string): void {
const source = readFileSync(cssPath, 'utf8').replace(/\/\*[\s\S]*?\*\//g, '')
const imports = [...source.matchAll(/@import\s+([^;]+);/g)]
for (const match of imports) {
const value = match[1].trim()
const isString = /^(['"])([^'"]+)\1$/.test(value)
const isUrl = /^url\(\s*(?:(['"])([^'"]+)\1|([^'")\s][^)]*?))\s*\)$/.test(value)
if (!isString && !isUrl) {
throw new Error(`${cssPath}: unsupported @import syntax: ${value}`)
}
}
} Prevention
- Always write @import with a quoted string path: @import 'file.css'; or @import "file.css";.
- If using url() syntax, ensure proper formatting: @import url('file.css');.
- Place layer()/supports() qualifiers after the quoted path, not inside it.
- Run the theme contract validator in CI to catch malformed @import statements.
When it happens
Trigger: A CSS file contains an @import with an unquoted bare path (e.g., @import file.css;), an @import with media queries written inline without proper wrapping, or a syntax that doesn't match the string or url() patterns. The validator processes every @import \s+([^;]+); match and rejects unparseable values.
Common situations: A developer writes @import without quotes (@import tokens/colors.css;). A CSS minifier or formatter rewrites @import into an unexpected format. An @import with a layer() or supports() qualifier that shifts the string/url match. A merge conflict artifact producing a broken @import.
Related errors
- [theme-contract] ${label} imports must be exactly: ${expecte
- [theme-contract] renderer theme must use the shared generate
- [theme-contract] renderer stylesheet ${fileName} cannot use
- [theme-contract] ${sourceName} declares invalid custom prope
- [theme-contract] ${sourceName} references invalid custom pro
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/4d62fc0fe02af158.
Report an issue: GitHub.