BloopAI/vibe-kanban · warning · Error
Approval has timed out
Error message
Approval has timed out
What it means
The approval feedback flow checks whether the pending approval's timeoutAt deadline has passed before submitting the user's denial reason. If current time exceeds timeoutAt it throws 'Approval has timed out' instead of calling denyAsync. This prevents sending feedback for approvals the executor has already expired/abandoned.
Source
Thrown at packages/web-core/src/features/workspace-chat/model/contexts/ApprovalFeedbackContext.tsx:112
setNowTs(Date.now());
reset();
},
[reset]
);
const exitFeedbackMode = useCallback(() => {
setActiveApproval(null);
setNowTs(Date.now());
reset();
}, [reset]);
const submitFeedback = useCallback(
async (message: string) => {
if (!activeApproval) return;
// Check timeout before submitting
if (new Date() > new Date(activeApproval.timeoutAt)) {
throw new Error('Approval has timed out');
}
await denyAsync({
approvalId: activeApproval.approvalId,
executionProcessId: activeApproval.executionProcessId,
reason: message.trim() || undefined,
});
setActiveApproval(null);
},
[activeApproval, denyAsync]
);
const value = useMemo(
() => ({
activeApproval,
enterFeedbackMode,
exitFeedbackMode,
submitFeedback,View on GitHub (pinned to 4deb7eca8f)
Solutions
- Clear the stale activeApproval state and show a timeout notice instead of letting the throw propagate
- Render a live countdown and disable the submit button once timeoutAt is reached
- Re-request the approval from the executor if the work is still needed
- If it fires unexpectedly early, check client/server clock skew (NTP)
Example fix
// before
await submitFeedback(reason); // throws if timed out
// after
try {
await submitFeedback(reason);
} catch (e) {
if (e.message === 'Approval has timed out') {
clearActiveApproval();
notify.info('This approval expired. Re-run the task to request a new one.');
}
} Defensive patterns
Strategy: try-catch
Validate before calling
if (activeApproval && new Date() > new Date(activeApproval.timeoutAt)) { clearActiveApproval(); return; } Type guard
function isApprovalLive(a: ActiveApproval | null): boolean { return !!a && new Date() <= new Date(a.timeoutAt); } Try / catch
try {
await submitFeedback(reason);
} catch (e) {
if (e instanceof Error && e.message === 'Approval has timed out') {
clearActiveApproval();
notify.info('Approval expired before submission.');
}
} Prevention
- Disable the deny/approve buttons once timeoutAt passes; show a countdown
- Clear expired approvals from context state proactively (interval check)
- Check client clock sync if timeouts appear to fire early
When it happens
Trigger: User leaves an approval dialog open longer than the approval TTL, then clicks submit/deny — new Date() > activeApproval.timeoutAt. Clock skew between client and server can also trigger it early.
Common situations: User steps away with a modal open (approval TTL typically minutes); long-running tool approval forgotten overnight; system clock changed or VM resumed from sleep shifting the local clock forward.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Missing required fields
- Timeout: process took more than 30 seconds to start
- Copy project files timed out after 30s
- Operation forcibly terminated due to hard timeout
AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29).
Data as JSON: /api/errors/8233ab84a55006d2.
Report an issue: GitHub.