Skip to Content
05 TroubleshootingTroubleshooting overlays

Troubleshooting overlays

Common issues when working with overlays and their solutions.


Overlay Not Applied

Symptom: You defined an overlay but the check still uses upstream settings.

Diagnosis

# Check overlay health aln override status # Look for issues aln override status --stale

Common Causes

1. Typo in Rule ID

Problem:

overlays: overrides: - selector: "rule[id=no-console-logs]" # Wrong: should be "no-console-log" set: severity: "error"

Solution:

# Find correct rule ID (inspect IR) cat .aligntrue/ir.json | jq '.rules[].id' # Fix overlay aln override remove 'rule[id=no-console-logs]' aln override add \ --selector 'rule[id=no-console-log]' \ --set severity=error

2. Selector Doesn’t Match

Problem: Selector doesn’t match any rules in the IR.

Error message:

✗ Overlay validation failed Selector matches no rules: rule[id=nonexistent-rule] Hint: Check rule ID spelling and ensure rule exists in IR

Solution:

# List available rules (feature not implemented yet) # For now, inspect IR directly: cat .aligntrue/ir.json | jq '.rules[].id' # Fix selector aln override remove 'rule[id=nonexistent-rule]' aln override add \ --selector 'rule[id=correct-rule-id]' \ --set severity=error

3. Property Path Invalid

Problem:

overlays: overrides: - selector: "nonexistent.property.path" set: value: "test"

Result: Selector doesn’t match any property in IR.

Solution:

Inspect IR structure and use correct path:

# View IR structure cat .aligntrue/ir.json | jq 'keys' # Use correct property path aln override add --selector 'profile.version' --set value="2.0.0"

4. Check Removed from Upstream

Problem: Upstream pack removed or renamed the check.

Diagnosis:

aln override status # Output: # ❌ rule[id=old-rule-name] # Set: severity=error # Healthy: stale (no match in IR)

Solution:

# Remove stale overlay aln override remove 'rule[id=old-rule-name]' # Find new rule ID (inspect IR) cat .aligntrue/ir.json | jq '.rules[].id' # Add overlay with new rule ID aln override add \ --selector 'rule[id=new-rule-name]' \ --set severity=error

Overlay Conflicts

Symptom: Multiple overlays target the same check or upstream changes conflict with overlay.

Multiple Overlays for Same Check

Problem:

overlays: overrides: - selector: "rule[id=no-console-log]" set: severity: "error" - selector: "rule[id=no-console-log]" set: severity: "warning" # Conflicts with above

Behavior: Last matching overlay wins. The second overlay overrides the first.

Solution (if unintended):

# Remove duplicate overlay aln override remove 'rule[id=no-console-log]' # Choose which one to keep and re-add it aln override add \ --selector 'rule[id=no-console-log]' \ --set severity=error

Solution (if intended):

Consolidate into single overlay:

overlays: overrides: # Single overlay with desired severity - selector: "rule[id=no-console-log]" set: severity: "error"

Upstream Changed Same Field

Problem: Upstream changed severity from warning to error, your overlay also sets error.

Diagnosis:

aln override diff 'rule[id=no-console-log]' # Output shows: # Original: severity=warning # With overlay: severity=error # (If upstream also changed to error, overlay is now redundant)

Solution:

Remove redundant overlay:

aln override remove 'rule[id=no-console-log]' # Overlay no longer needed (upstream matches your preference)

Three-Way Merge Conflict

Problem: Upstream changed field you didn’t override, but your overlay now conflicts.

Example:

# Original upstream check: id: max-complexity severity: warning inputs: threshold: 10 # Your overlay (before upstream update) overlays: overrides: - selector: "rule[id=max-complexity]" set: "check.inputs.threshold": 15 # Upstream update check: id: max-complexity severity: error # Changed inputs: threshold: 12 # Changed excludeComments: true # Added

Result: Your overlay still sets threshold: 15, but upstream changed to 12 and added excludeComments.

Diagnosis:

aln override diff 'rule[id=max-complexity]' # Shows original vs overlayed result

Solution options:

Option A: Keep your overlay (ignore upstream input change):

# No action needed, overlay applies as-is aln sync

Option B: Merge manually:

# Remove old overlay aln override remove 'rule[id=max-complexity]' # Add new overlay with merged inputs aln override add \ --selector 'rule[id=max-complexity]' \ --set check.inputs.threshold=15 \ --set check.inputs.excludeComments=true

Option C: Accept upstream (remove overlay):

aln override remove 'rule[id=max-complexity]'

Ambiguous Selector

Symptom: Overlay matches multiple rules unintentionally.

Selector Matches Multiple Rules

Problem: Selector is ambiguous and matches more than one rule.

Example:

overlays: overrides: # If multiple rules have same ID (from different sources) - selector: "rule[id=no-console-log]" set: severity: "error"

Result: Overlay applies to all matching rules (may be unintended).

Diagnosis:

aln override status # Output shows if overlay matches multiple rules

Solution:

Make selector more specific or accept that it applies to all matches. Currently, selectors apply to all matching rules. For more granular control, use property paths or array indices to target specific instances.


Expired Overlays

Symptom: Overlay has passed expiration date but still applies.

How Expiration Works

Key point: Expiration is advisory only. Overlays continue to apply after expiration but show warnings.

Diagnosis:

aln override status # Output: # ⚠ rule[id=no-deprecated-api] # Set: severity=warning # Healthy: yes # Note: Check YAML comments for expiration tracking

Solution:

Review YAML comments and decide:

Option A: Extend expiration (update YAML comment):

overlays: overrides: # TEMPORARY: Migration extended # Expires: 2025-12-31 (was 2025-10-15) - selector: "rule[id=no-deprecated-api]" set: severity: "warning"

Option B: Remove overlay:

# Migration complete, remove override aln override remove 'rule[id=no-deprecated-api]'

Option C: Make permanent (update YAML comment):

overlays: overrides: # PERMANENT: Legacy code exception # Owner: platform-team - selector: "rule[id=no-deprecated-api]" set: severity: "warning"

Automated Expiration Audits

Add to CI:

# .github/workflows/validate.yml - name: Check for expired overlays run: | aln override status --stale --json > stale-overlays.json if [ $(jq '.expired | length' stale-overlays.json) -gt 0 ]; then echo "⚠️ Expired overlays detected" jq '.expired' stale-overlays.json exit 1 # Fail CI fi

Plug Slot Overlap

Symptom: Overlay and plug both try to customize same field.

Problem Example

Overlay:

overlays: overrides: - selector: "rule[id=ai-prompt-template]" set: "check.inputs.context": "production code"

Plug:

plugs: - id: "cursor-context" agent: cursor slots: context: "local development" # Conflicts with overlay

Result: Undefined behavior (plug or overlay may win depending on merge order).

Diagnosis

# Check overlay status aln override status # Check plug status aln plugs status # Look for overlapping fields

Solution

Rule: Overlays handle pack-level customization, plugs handle agent-specific config.

Option A: Use overlay for pack changes:

# Remove plug slot plugs: - id: "cursor-context" agent: cursor # Removed: slots.context # Keep overlay (applies to all agents) overlays: overrides: - selector: "rule[id=ai-prompt-template]" set: "check.inputs.context": "production code"

Option B: Use plug for agent-specific override:

# Remove overlay overlays: overrides: [] # Keep plug (Cursor-specific) plugs: - id: "cursor-context" agent: cursor slots: context: "local development"

Decision tree:

  • Same value for all agents? Use overlay
  • Agent-specific value? Use plug
  • Both needed? Pick one or redesign (avoid overlap)

Overlay Not Validated in CI

Symptom: Overlay passes locally but fails in CI.

Common Causes

1. Lockfile Drift

Problem: Local overlay applied but lockfile not committed.

CI error:

✗ Lockfile validation failed Lockfile out of sync with rules - Overlay hash mismatch for @acme/standards Hint: Run 'aln sync' locally and commit lockfile

Solution:

# Regenerate lockfile locally aln sync # Commit lockfile git add .aligntrue.lock.json git commit -m "chore: Update lockfile with overlay" git push

2. Team Mode Not Enabled in CI

Problem: Local has team mode, CI uses solo mode.

Solution:

Ensure CI config matches local:

# .aligntrue/config.yaml (must be committed) mode: team modules: lockfile: true bundle: true

3. Missing Source in CI

Problem: Overlay targets git source not pulled in CI.

CI error:

✗ Overlay validation failed Pack not found: @acme/standards Hint: Ensure git sources are pulled in CI

Solution:

Add source pull to CI:

# .github/workflows/validate.yml - name: Pull sources run: aln pull https://github.com/acme/standards --offline # Use cache - name: Validate run: aln check --ci

Or vendor pack:

# Vendor pack (commit to repo) git submodule add https://github.com/acme/standards vendor/acme-standards aln link https://github.com/acme/standards --path vendor/acme-standards # CI will have pack without network call

When to Fork Instead

Symptom: You have many overlays or complex customizations.

Indicators You Should Fork

Don’t overlay if:

  • You have >5 overlays for same pack
  • You’re changing check logic (not just severity/inputs)
  • You need to add new checks
  • Upstream updates are irrelevant to you
  • Your requirements diverge fundamentally

Fork instead:

# Clone upstream pack git clone https://github.com/acme/standards my-standards # Customize freely cd my-standards # Edit .aligntrue.yaml with your changes # Vendor in your project cd /path/to/your/project git submodule add https://github.com/yourorg/my-standards vendor/my-standards aln link https://github.com/yourorg/my-standards --path vendor/my-standards

Hybrid Approach

Fork for major changes, overlay for minor tweaks:

# Use your fork as base sources: - git: https://github.com/yourorg/my-standards path: vendor/my-standards # Overlay minor adjustments overlays: overrides: # TEMPORARY: Migration strictness # Expires: 2025-12-31 - selector: "rule[id=specific-check]" set: severity: "error"

Debug Commands

Inspect Overlay Application

# Show all overlays aln override status # Show overlay for specific rule aln override diff 'rule[id=no-console-log]' # JSON output for scripting aln override status --json | jq '.overlays[] | select(.healthy == false)'

Validate Overlays

# Validate overlay application aln override status # Dry-run sync to see effects aln sync --dry-run # Check drift (includes overlay drift) aln drift

Inspect Lockfile

# View overlay hashes in lockfile cat .aligntrue.lock.json | jq '.dependencies[] | {pack: .id, overlay_hash: .overlay_hash}' # Compare overlay hash between runs git diff .aligntrue.lock.json

Common Error Messages

”Overlay validation failed: Selector matches no rules”

Cause: Selector doesn’t match any rules in IR.

Fix:

# List available rules (inspect IR) cat .aligntrue/ir.json | jq '.rules[].id' # Update overlay with correct selector aln override remove 'rule[id=wrong-id]' aln override add \ --selector 'rule[id=correct-id]' \ --set severity=error

“Overlay validation failed: Invalid selector syntax”

Cause: Selector syntax is incorrect.

Fix:

# Check selector format # Valid formats: # - 'rule[id=value]' (quotes required) # - property.path # - array[0] # Update overlay with correct syntax aln override add \ --selector 'rule[id=correct-format]' \ --set severity=error

“Overlay conflict: Duplicate selector”

Cause: Multiple overlays have identical selectors.

Fix:

# View all overlays aln override status # Remove duplicate (interactive) aln override remove

“Lockfile drift detected: Overlay hash mismatch”

Cause: Overlay changed but lockfile not updated.

Fix:

# Regenerate lockfile aln sync # Commit lockfile git add .aligntrue.lock.json git commit -m "chore: Update lockfile"

Best Practices to Avoid Issues

1. Use Specific Selectors

# ✅ Good: Specific rule ID overlays: overrides: - selector: "rule[id=no-console-log]" set: severity: "error" # ❌ Bad: Too vague (if property path is ambiguous) overlays: overrides: - selector: "severity" # Might match multiple properties set: value: "warning"

2. Document Reasons

# ✅ Good: Clear reason with YAML comments overlays: overrides: # CLI tool requires console output for user feedback # Owner: cli-team - selector: "rule[id=no-console-log]" set: severity: "off" # ❌ Bad: No context overlays: overrides: - selector: "rule[id=no-console-log]" set: severity: "off"

3. Set Expiration for Temporary Overrides

# ✅ Good: Expires after migration overlays: overrides: # TEMPORARY: Gradual rollout # Expires: 2025-12-31 - selector: "rule[id=new-security-rule]" set: severity: "warning" # ❌ Bad: No expiration (forgotten override) overlays: overrides: - selector: "rule[id=new-security-rule]" set: severity: "warning"

4. Audit Regularly

# Monthly audit aln override status # Check for redundant overlays aln override diff # Validate in CI aln drift

5. Use Dot Notation for Nested Properties

# ✅ Good: Dot notation for nested properties overlays: overrides: - selector: "rule[id=max-complexity]" set: "check.inputs.threshold": 15 "check.inputs.excludeComments": true # ❌ Bad: Won't work (overlays don't support nested objects in set) overlays: overrides: - selector: "rule[id=max-complexity]" set: check: inputs: threshold: 15

  • Overlays Guide: docs/overlays.md - Complete overlay documentation
  • Commands: docs/commands.md - CLI reference for overlay commands
  • Drift Detection: docs/drift-detection.md - Automated staleness checks
  • Team Mode: docs/team-mode.md - Team approval workflows
  • Git Sources: docs/git-sources.md - Working with upstream packs

Still Having Issues?

  1. Check lockfile: cat .aligntrue.lock.json | jq '.dependencies[] | select(.overlay_hash != null)'
  2. Validate overlays: aln check --validate-overlays
  3. Review drift: aln drift --json | jq '.categories.overlay_staleness'
  4. Inspect health: aln override status --stale

If none of these resolve the issue, file a bug report with:

  • Output of aln override status
  • Contents of .aligntrue.yaml (overlays section)
  • Lockfile excerpt (if team mode)
  • Expected vs actual behavior
Last updated on