n8n-io/n8n · warning
SDK_UNSOLICITED_STICKY
SDK_UNSOLICITED_STICKY
Error message
Do not add sticky() / stickyNote nodes unless the user explicitly asked for canvas notes. Put explanations in the chat reply instead.
What it means
The linter flags any call to the `sticky()` factory. Sticky notes are canvas annotations, not workflow logic; the SDK guidance is to add them only when the user has explicitly asked for a note on the canvas. Unprompted `sticky()` calls clutter the workflow and push explanation into a place users miss, so the walker emits `SDK_UNSOLICITED_STICKY` (workflow-sdk-lint.ts:251-262) for every `sticky(...)` invocation, regardless of arguments.
Source
Thrown at packages/@n8n/workflow-sdk/src/lint/sdk/workflow-sdk-lint.ts:254
if (!isPropertyName && !isObjectKey && !isSafeMethodObject) {
issues.push(
lintIssue({
code: 'SDK_FORBIDDEN_CONSTRUCT',
message: `Global '${node.name}' is unavailable in SDK builder code. Move runtime logic to a Code node or expr().`,
...locationOf(node),
lintTarget: 'sdk',
}),
);
}
}
if (node.type !== 'CallExpression') return;
const call = node;
if (call.callee.type === 'Identifier' && call.callee.name === 'sticky') {
issues.push(
lintIssue({
code: 'SDK_UNSOLICITED_STICKY',
message:
'Do not add sticky() / stickyNote nodes unless the user explicitly asked for canvas notes. ' +
'Put explanations in the chat reply instead.',
...locationOf(call),
lintTarget: 'sdk',
}),
);
}
if (
call.callee.type === 'MemberExpression' &&
!call.callee.computed &&
call.callee.property.type === 'Identifier'
) {
const method = call.callee.property.name;
if (method === 'onTrue' || method === 'onFalse') {
// Only count direct `ifNode.onTrue(...)` / `ifNode.onFalse(...)`.View on GitHub (pinned to 5ac6606e81)
Solutions
- Remove the `sticky()` call entirely and put the explanation in the chat reply / PR description instead.
- Only re-add `sticky()` if the user has explicitly asked for canvas notes; if so, accept that the lint warning is expected and review it during PR.
- If a note is genuinely required, prefer `sticky()` with concise user-facing text and no internal commentary.
Example fix
// before
sticky('This node fetches users from the API and filters by active status.');
workflow().to(httpNode).to(filterNode);
// after — explanation goes in the chat reply, not the canvas
workflow().to(httpNode).to(filterNode); Defensive patterns
Strategy: validation
Validate before calling
import { parse } from 'acorn';
function hasUnsolicitedSticky(builderSource: string): boolean {
const ast = parse(builderSource, { ecmaVersion: 'latest', sourceType: 'module', locations: true });
let found = false;
walk(ast, (n) => {
if (n.type === 'CallExpression' && n.callee.type === 'Identifier' && n.callee.name === 'sticky') {
found = true;
}
});
return found;
} Type guard
import type { Node, CallExpression } from 'estree';
const isStickyCall = (n: Node): n is CallExpression =>
n.type === 'CallExpression' && n.callee.type === 'Identifier' && n.callee.name === 'sticky'; Prevention
- Default to putting explanations in the chat reply, never on the canvas.
- Only emit `sticky()` when the user has explicitly asked for a note.
- Run the SDK linter on generated workflows and treat `SDK_UNSOLICITED_STICKY` as a generation bug.
When it happens
Trigger: Calling `sticky('explanation text')`, `stickyNote(...)`, or any `CallExpression` whose callee is an `Identifier` named `sticky` in builder source. There is no argument-based exemption — any such call fires.
Common situations: AI agents annotate generated workflows with sticky notes explaining each step. Agents use `sticky()` as a substitute for in-chat explanations. Treating sticky notes as inline documentation.
Related errors
- SDK_PLACEHOLDER_WRAPPED
- Thread ${threadId}: ${buildSignalIds.size} workflow(s) were
- Unsupported syntax: '${nodeType}' is not allowed in SDK code
- '${node.kind}' declarations are not allowed. Use 'const' onl
- Sticky notes do not support input connections
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/0248508b1db183ab.
Report an issue: GitHub.