twentyhq/twenty · error · Error
getPublicAssetUrl can only be called from within a logic fun
Error message
getPublicAssetUrl can only be called from within a logic function or front component
What it means
Thrown by getPublicAssetUrl when process.env[DEFAULT_API_URL_NAME] or process.env[DEFAULT_APP_ACCESS_TOKEN_NAME] is unset. Twenty injects these two env vars only while dispatching a logic function or front component, so the guard detects calls from any other execution context and refuses to build a URL it cannot authenticate or scope.
Source
Thrown at packages/twenty-sdk/src/sdk/utils/get-public-asset-url.ts:25
token: string,
): { workspaceId: string; applicationId: string } => {
const payload = JSON.parse(atob(token.split('.')[1]));
return {
workspaceId: payload.workspaceId,
applicationId: payload.applicationId,
};
};
// Returns the public URL for a file in the app's public/ directory.
// Works in both logic functions and front components.
// The path is relative to the public/ folder (e.g. "images/logo.png").
export const getPublicAssetUrl = (path: string): string => {
const apiUrl = process.env[DEFAULT_API_URL_NAME];
const token = process.env[DEFAULT_APP_ACCESS_TOKEN_NAME];
if (!apiUrl || !token) {
throw new Error(
'getPublicAssetUrl can only be called from within a logic function or front component',
);
}
const { workspaceId, applicationId } = decodeTokenPayload(token);
const withoutLeadingSlash = path.startsWith('/') ? path.slice(1) : path;
const withPublicPrefix = withoutLeadingSlash.startsWith('public/')
? withoutLeadingSlash
: `public/${withoutLeadingSlash}`;
const encodedPath = withPublicPrefix
.split('/')
.map(encodeURIComponent)
.join('/');
return `${apiUrl}/public-assets/${workspaceId}/${applicationId}/${encodedPath}`;
};
View on GitHub (pinned to 1f5dd2bbd2)
Solutions
- Move the call inside a logic function or front component handler body so Twenty's runtime has already set the env vars.
- In tests, set process.env[DEFAULT_API_URL_NAME] and process.env[DEFAULT_APP_ACCESS_TOKEN_NAME] (import the constant names from twenty-shared/application) before invoking.
- Avoid invoking getPublicAssetUrl at module load time; defer it into the handler so it only runs in runtime context.
Example fix
// before (module scope, breaks)
export const logo = getPublicAssetUrl('images/logo.png');
// after (inside a logic/front handler)
export const handler = () => {
const logo = getPublicAssetUrl('images/logo.png');
return { logo };
}; Defensive patterns
Strategy: validation
Validate before calling
import { DEFAULT_API_URL_NAME, DEFAULT_APP_ACCESS_TOKEN_NAME } from 'twenty-shared/application';
const canCallGetPublicAssetUrl = (): boolean =>
Boolean(process.env[DEFAULT_API_URL_NAME]) &&
Boolean(process.env[DEFAULT_APP_ACCESS_TOKEN_NAME]);
// before calling:
if (!canCallGetPublicAssetUrl()) {
// skip or seed env vars in tests
} Prevention
- Only import and call getPublicAssetUrl from within logic function or front component handlers.
- In unit tests, set both DEFAULT_API_URL_NAME and DEFAULT_APP_ACCESS_TOKEN_NAME env vars before invoking.
- Never evaluate getPublicAssetUrl at module top level; defer into the handler body.
When it happens
Trigger: Calling getPublicAssetUrl('images/logo.png') outside a Twenty-dispatched logic/front runtime: in a Jest test, a Node CLI script, a module top-level statement, or a worker that never received the app access token.
Common situations: Unit-testing SDK helpers without seeding the two env vars; importing SDK code into server bootstrap that runs before the runtime sets the token; SSR/build-time evaluation of a module that transitively reaches getPublicAssetUrl.
Related errors
- ${caller}() requires the app runtime env vars ${DEFAULT_API_
- Missing API url. Set the `${DEFAULT_API_URL_NAME}` environme
- Missing application access token. Set the `${DEFAULT_APP_ACC
- createCompany did not return an id
- createPerson did not return an id
AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12).
Data as JSON: /api/errors/cf8c7e57400be569.
Report an issue: GitHub.