lib/streamlit/.agents/skills/developing-with-streamlit/references/ccv2-troubleshooting.md
asset_dir, component key)key= vs frontend key)isolate_styles surprisesThe single most common cause of broken CCv2 components is accidentally mixing in v1 APIs from outdated examples, blog posts, or training data. v1 is deprecated and will not work.
Symptoms:
Streamlit is not defined errors in browser consolesetComponentValue is not a function errorsCheck your code for these banned patterns and replace them:
| Banned (v1) | Correct (v2) |
|---|---|
st.components.v1 | st.components.v2.component(...) |
components.declare_component() | st.components.v2.component(...) |
components.html() | st.components.v2.component(...) with html= |
Streamlit.setComponentValue(val) | setStateValue("key", val) or setTriggerValue(...) |
Streamlit.setFrameHeight() | Remove entirely (v2 handles sizing) |
Streamlit.setComponentReady() | Remove entirely (v2 has no ready signal) |
window.Streamlit | Use destructured args from export default function |
window.parent.postMessage(...) | Use setStateValue / setTriggerValue |
streamlit-component-lib (npm) | @streamlit/component-v2-lib (if types needed) |
function sendMessageToStreamlitClient | Remove entirely; use v2 callback args |
Fix: search all .py and .js/.ts/.tsx files for these patterns. If any are found, rewrite using the v2 equivalents above. The cookiecutter template generates correct v2 code — if you started from the template, the contamination is in your customizations.
asset_dir, component key)You passed a path-like js=/css= string (like index-*.js or assets/index-*.js) but Streamlit can’t find an asset_dir for this component key.
Fix:
pyproject.toml with [[tool.streamlit.component.components]] ... asset_dir = ...st.components.v2.component("<project>.<component>", js="...", css="...") with the matching fully-qualified key.Important context:
streamlit run ... for packaged verification because manifest discovery is part of Streamlit runtime initialization.CCv2 uses a heuristic: strings that “look like” paths are treated as file references. A multi-line string is always treated as inline content.
Fix:
html/css/js.js=/css=; add a newline if you must.Globs must match exactly one file under asset_dir.
Fix:
index-<hash>.js / index-<hash>.css (or assets/index-<hash>... if you emit into an assets/ subdir).component-template, run npm run clean from your frontend/ directory to clear the build/ output so index-*.js matches exactly one file.Symptoms:
streamlit-component-x / streamlit_component_x remain in paths or metadata.Fix:
pyproject.toml project nameMANIFEST.in paths[tool.setuptools.packages.find] and [tool.setuptools.package-data]<import_name>/pyproject.toml)"<project.name>.<component.name>")default={...} doesn’t apply / missing result attributesDefaults only apply to state keys, and Streamlit expects those keys to be declared via on_<key>_change callback parameters at mount time.
Fix:
default={"value": ...}, also pass on_value_change=lambda: None.None.key= vs frontend key)key= is the user-visible Streamlit element key.key string that is generated by Streamlit and is not the same as the Python key unless you explicitly pass the user key through data.Fix:
data={"user_key": key, ...}.isolate_styles surprisesisolate_styles=True) surprisesWith isolate_styles=True (default):
parentElement is a ShadowRoot.Fix:
isolate_styles=True for safety and use CSS variables and component-local styles.isolate_styles=False only when you intentionally need global styling behavior.If you deviate from the template’s Vite config (or you’re wiring Vite into an existing repo), these are the common footguns:
base: "./": relative asset URLs can break when served from Streamlit’s component URL path.index-*.js can match multiple files. Clean the build dir before rebuilding.If you directly set parentElement.innerHTML = ..., you can overwrite the HTML/CSS that Streamlit injected from your html=/css= arguments.
Fix:
querySelector + modifying children.innerHTML.