Crosstalk-Solutions/project-nomad · warning

guard.warnings.join(' ')

Error message

guard.warnings.join(' ')

What it means

A 409 from createCustomApp when evaluateCustomApp produced warnings (risky host paths, untrusted or moving-tag images like :latest) and the request did not set force=true. Unlike blocks, warnings are overridable.

Source

Thrown at admin/app/controllers/system_controller.ts:407

        if (duplicateHostPorts.length) {
            return response.status(422).send({
                success: false,
                message: `Duplicate host port(s): ${duplicateHostPorts.join(', ')}. Each host port can map to only one container.`,
            })
        }

        // Security guardrails: hard-block dangerous bind mounts / malformed images regardless of
        // force; surface overridable warnings (risky paths, untrusted/moving-tag images) unless forced.
        const guard = evaluateCustomApp({ image: payload.image, volumes: payload.volumes })
        if (guard.blocked.length) {
            return response.status(422).send({
                success: false,
                message: guard.blocked.join(' '),
                blocked: guard.blocked,
            })
        }
        if (!payload.force && guard.warnings.length) {
            return response.status(409).send({
                success: false,
                message: guard.warnings.join(' '),
                warnings: guard.warnings,
            })
        }

        // Advisory preflight: surface port conflicts before creating the record so a failed
        // install doesn't leave a phantom card. The user can re-submit with force=true to override.
        if (!payload.force && hostPorts.length) {
            const { conflicts } = await this.dockerService.checkPortConflicts(hostPorts)
            if (conflicts.length) {
                return response.status(409).send({
                    success: false,
                    message: `Port conflict: ${conflicts
                        .map((c) => `${c.port} (in use by ${c.usedBy})`)
                        .join(', ')}.`,
                    portConflicts: conflicts,
                })

View on GitHub (pinned to 0bd1c6f4f9)

Solutions

  1. Review guard.warnings in the response body
  2. Pin the image to an immutable tag/digest or narrow the mounted path, then re-submit
  3. If the risk is accepted, re-submit the identical request with force: true

Example fix

// before
{ image: 'someapp:latest', ... }
// after
{ image: 'someapp:1.2.3', ... }
Defensive patterns

Strategy: validation

Validate before calling

if (image.endsWith(':latest')) requireForceConfirmation();

Try / catch

try { await create(payload); } catch (e) { if (e.status === 409 && e.warnings) confirmForce(e.warnings); }

Prevention

When it happens

Trigger: POST create-custom-app without force=true while specifying an image with a mutable tag (latest) or volumes touching risky paths (e.g. /home, /etc subpaths).

Common situations: Installing a community image tagged :latest, or mounting broad host directories that risk data exposure.

Related errors


AI-assisted analysis of Crosstalk-Solutions/project-nomad@0bd1c6f4f9 (2026-08-27). Data as JSON: /api/errors/f145305fe4ae2e8d. Report an issue: GitHub.