toeverything/AFFiNE · error · BlockSuiteError
ValueNotExists
ValueNotExists
Error message
EmbedIframeService or LinkPreviewService not found
What it means
parseIdentifier accepts only two shapes: an Identifier created by createIdentifier (a callable carrying identifierName/variant), or a named class/constructor from which a stable name+hash identifier is derived. Anything else — strings, undefined, numbers, plain objects, anonymous functions — cannot be mapped to a service key, so it throws 'Input is not a service identifier.' before any registry lookup happens. Unlike string-token DI libraries (inversify/tsyringe), raw strings are not valid tokens here.
Solutions
- Create identifiers with createIdentifier<T>('Name') and pass that callable to impl/get/getAll
- Fix the circular import so the identifier is defined when get()/impl() runs — move identifiers to a leaf module or reorder imports
- Never pass strings or plain objects as identifiers; if you meant class-as-identifier, pass the class itself (it must have a .name)
Example fix
// before
provider.get('Storage'); // strings are not identifiers
// after
const Storage = createIdentifier<Storage>('Storage');
fw.impl(Storage, LocalStorage);
provider.get(Storage); Defensive patterns
Strategy: type-guard
Validate before calling
null
Type guard
function isIdentifier<T>(x: unknown): x is Identifier<T> {
return typeof x === 'function' && typeof (x as any).identifierName === 'string';
}
// guard before resolving
if (!isIdentifier(Storage)) throw new Error('Storage identifier not initialized (circular import?)');
provider.get(Storage); Prevention
- Always create tokens with createIdentifier() — string tokens are not supported
- Keep identifier modules leaf-level (no imports of consumers) to avoid circular-import undefined tokens
- If an identifier can arrive from untrusted wiring, isIdentifier() it before calling get/impl
When it happens
Trigger: provider.get('Storage') expecting a string token; passing undefined because a circular ESM import left the identifier module half-evaluated; passing a plain object or a value obtained by destructuring/wrapping the Identifier; passing an anonymous function expression (empty .name).
Common situations: Migrating code from a string-token DI container; circular imports where `export const Storage = createIdentifier(...)` is consumed before evaluation; identifiers re-exported through barrel files involved in a cycle.
Related errors
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/b82554e20730244b.
Report an issue: GitHub.
Appendix: source
Thrown at blocksuite/affine/blocks/embed/src/embed-iframe-block/embed-iframe-block.ts:163
};
refreshData = async () => {
try {
const { url } = this.model.props;
if (!url) {
this.status$.value = 'idle';
return false;
}
// set loading status
this.status$.value = 'loading';
this.error$.value = null;
// get embed data
const embedIframeService = this.embedIframeService;
const linkPreviewService = this.linkPreviewService;
if (!embedIframeService || !linkPreviewService) {
throw new BlockSuiteError(
ErrorCode.ValueNotExists,
'EmbedIframeService or LinkPreviewService not found'
);
}
// get embed data and preview data in a promise
const [embedData, previewData] = await Promise.all([
embedIframeService.getEmbedIframeData(url),
linkPreviewService.query(url),
]);
// if the embed data is not found, and the iframeUrl is not set, throw an error
const currentIframeUrl = this.model.props.iframeUrl;
if (!embedData && !currentIframeUrl) {
throw new BlockSuiteError(
ErrorCode.ValueNotExists,
'Failed to get embed data'
);View on GitHub (pinned to b4c8548c09)